Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough스낵바를 문자열 기반에서 타입 기반( Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant UI as CommonAnswerRoute (UI)
participant VM as CommonAnswerViewModel
participant Nav as NavController
participant Snack as LocalSnackBarTrigger
User->>UI: 더보기/옵션 선택
UI->>VM: onClickMoreOptions()/onOptionClicked(option)
VM-->>UI: uiState 업데이트(showBottomSheet)
VM->>VM: 처리 (BLOCK/REPORT)
VM-->>Snack: emit ShowSnackBar(snackBarType)
alt Navigate after action
VM-->>Nav: emit NavigateToQuest
end
Snack->>UI: render via CustomSnackBarVisuals -> CustomSnackBar
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt (1)
186-193:⚠️ Potential issue | 🔴 Critical
onAnswerClick에 하드코딩된 값1이 전달되고 있습니다.현재
onAnswerClick(1)로 하드코딩되어 있어, 어떤 답변 항목을 클릭해도 항상 answerId가 1로 전달됩니다. 실제 답변의 ID를 전달해야 합니다.🐛 수정 제안
items( items = state.answers, key = { it.answerId }, ) { answer -> CommonAnswerItem( answer = answer, - onClick = { onAnswerClick(1) }, + onClick = { onAnswerClick(answer.answerId) }, modifier = Modifier .padding(horizontal = screenWidthDp(24.dp)) .padding(bottom = screenHeightDp(24.dp)), ) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt` around lines 186 - 193, The onClick for CommonAnswerItem is passing a hardcoded 1 to onAnswerClick; change it to pass the clicked answer's ID (e.g., use answer.id or answer.answerId depending on the model) so the real answer identifier is forwarded to onAnswerClick; update the onClick lambda in CommonAnswerItem to call onAnswerClick with the answer's id property (and add a null/exists check if the model uses a nullable id).
🧹 Nitpick comments (13)
app/src/main/res/drawable/ic_report.xml (1)
10-26: 색상 하드코딩 대신 색상 리소스 참조로 바꾸는 것을 권장합니다.
#FF3B3E가 여러 path에 중복되어 있어 추후 테마 대응(다크모드/브랜드 컬러 변경) 시 유지보수 비용이 커집니다.@color/...로 추출해 공통 관리하는 편이 안전합니다.♻️ 제안 diff
- android:strokeColor="#FF3B3E"/> + android:strokeColor="@color/snackbar_alert_icon"/> - android:strokeColor="#FF3B3E" + android:strokeColor="@color/snackbar_alert_icon" - android:fillColor="#FF3B3E"/> + android:fillColor="@color/snackbar_alert_icon"/> - android:fillColor="#FF3B3E"/> + android:fillColor="@color/snackbar_alert_icon"/>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/res/drawable/ic_report.xml` around lines 10 - 26, 해당 XML의 여러 path 요소(android:strokeColor 및 android:fillColor)에 하드코딩된 색상값 "#FF3B3E"가 중복되어 있으니 colors.xml에 예: <color name="ic_report_tint">#FF3B3E</color> 같은 리소스를 추가한 뒤 ic_report.xml의 모든 android:strokeColor 및 android:fillColor="#FF3B3E"를 `@color/ic_report_tint로` 교체하세요; 변경 대상 식별에는 각 <path> 요소의 android:pathData 값(예: "M18,16H6V9.538...", "M4,20L20,20", "M12.005,6.5...", "M12,12.5m-1,0...")과 속성 이름(strokeColor, fillColor)을 참고하면 됩니다.app/src/main/res/drawable/ic_overflow_menu.xml (1)
1-9: 전반적으로 LGTM, 색상 리소스 사용 고려 권장벡터 드로어블 구조와 아이콘 형태는 적절합니다. 다만
fillColor가#ffffff로 하드코딩되어 있어 다크/라이트 테마 지원이나 다른 배경에서의 재사용성이 제한될 수 있습니다.스낵바 등 특정 UI에서만 사용될 경우 현재 구현도 무방하지만, 향후 유연성을 위해 색상 리소스나 테마 속성 사용을 고려해 보세요.
♻️ 색상 리소스 사용 제안
<path android:pathData="M12,16.5C12.398,16.5 12.779,16.658 13.061,16.939C13.342,17.221 13.5,17.602 13.5,18C13.5,18.398 13.342,18.779 13.061,19.061C12.779,19.342 12.398,19.5 12,19.5C11.602,19.5 11.221,19.342 10.939,19.061C10.658,18.779 10.5,18.398 10.5,18C10.5,17.602 10.658,17.221 10.939,16.939C11.221,16.658 11.602,16.5 12,16.5ZM12,10.5C12.398,10.5 12.779,10.658 13.061,10.939C13.342,11.221 13.5,11.602 13.5,12C13.5,12.398 13.342,12.779 13.061,13.061C12.779,13.342 12.398,13.5 12,13.5C11.602,13.5 11.221,13.342 10.939,13.061C10.658,12.779 10.5,12.398 10.5,12C10.5,11.602 10.658,11.221 10.939,10.939C11.221,10.658 11.602,10.5 12,10.5ZM12,4.5C12.398,4.5 12.779,4.658 13.061,4.939C13.342,5.221 13.5,5.602 13.5,6C13.5,6.398 13.342,6.779 13.061,7.061C12.779,7.342 12.398,7.5 12,7.5C11.602,7.5 11.221,7.342 10.939,7.061C10.658,6.779 10.5,6.398 10.5,6C10.5,5.602 10.658,5.221 10.939,4.939C11.221,4.658 11.602,4.5 12,4.5Z" - android:fillColor="#ffffff"/> + android:fillColor="@color/white"/> </vector>또는 런타임에
ImageView.setColorFilter()또는app:tint를 사용하여 아이콘 색상을 동적으로 적용하는 방법도 있습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/res/drawable/ic_overflow_menu.xml` around lines 1 - 9, Replace the hardcoded android:fillColor="#ffffff" in the <path> of the vector drawable with a color resource or theme attribute so the icon follows dark/light themes and can be reused; e.g. change android:fillColor to a reference like `@color/overflow_icon` or a theme attribute like ?attr/colorOnSurface (or make the vector tintable and remove the fillColor so callers can set app:tint or ImageView.setColorFilter), update the color resource if needed, and ensure usages apply the intended tint/theme attribute.app/src/main/res/drawable/ic_block.xml (1)
6-8:clip-path는 제거해도 동일하게 동작합니다.Line 7-8은 전체 캔버스를 그대로 클리핑해서 렌더링 결과 변화가 없습니다. 단순화를 위해 제거를 권장합니다.
Diff 제안
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - <group> - <clip-path - android:pathData="M0,0h24v24h-24z"/> <path android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0" android:strokeWidth="2" android:fillColor="#00000000" android:strokeColor="#ffffff"/> <path android:pathData="M6.327,17.26L17.327,7.26" android:strokeWidth="2" android:fillColor="#00000000" android:strokeColor="#ffffff"/> - </group> </vector>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/res/drawable/ic_block.xml` around lines 6 - 8, SVG/XML contains an unnecessary clip-path that clips the whole canvas (the <clip-path> element with android:pathData="M0,0h24v24h-24z"); remove that <clip-path> element (and its enclosing empty group if it becomes redundant) from ic_block.xml so the drawable is simplified without changing rendering.app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt (1)
60-60: Spacer에padding대신height사용 필요Line 60에서
Spacer에padding을 사용하고 있습니다.padding은 모든 방향에 여백을 추가하므로 의도한 12dp가 아닌 24dp(위아래 합산)의 수직 공간이 생깁니다. Line 70처럼height를 사용해야 합니다.♻️ 수정 제안
- Spacer(modifier = Modifier.padding(screenHeightDp(12.dp))) + Spacer(modifier = Modifier.height(screenHeightDp(12.dp)))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt` at line 60, In MyAnswerItem (file MyAnswerItem.kt) the Spacer uses Modifier.padding(screenHeightDp(12.dp)) which adds padding both top and bottom (totaling 24dp) instead of providing a 12dp vertical gap; change the Spacer's modifier to Modifier.height(screenHeightDp(12.dp)) so it produces the intended 12dp vertical space (refer to the Spacer instance around the commented line and mirror the approach used later on line 70).app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)
84-90: 불필요한viewModelScope.launch블록현재
when블록 내에 suspend 함수 호출이 없어viewModelScope.launch가 불필요합니다. TODO 구현 시 실제 비동기 작업이 추가되면 필요하겠지만, 현재로서는 제거하거나 실제 구현 시 추가하는 것이 더 명확합니다.♻️ 선택적 수정 제안
fun onOptionClick(option: OptionType) { onDismissBottomSheet() - viewModelScope.launch { - when (option) { - OptionType.EDIT -> { /* TODO 수정 화면 이동 */ } - OptionType.DELETE -> { /* TODO 삭제 모달 띄우기 */ } - else -> {} - } + when (option) { + OptionType.EDIT -> { /* TODO 수정 화면 이동 */ } + OptionType.DELETE -> { /* TODO 삭제 모달 띄우기 */ } + else -> {} } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt` around lines 84 - 90, The current viewModelScope.launch wrapper around the when(option) block is unnecessary because there are no suspend calls; remove the viewModelScope.launch call and execute the when(option) directly (retaining the OptionType.EDIT and OptionType.DELETE branches) and only reintroduce viewModelScope.launch around the when when you implement actual asynchronous work for those branches (or make the called functions suspend and keep the launch). Refer to the viewModelScope.launch and the when(option) handling OptionType.EDIT / OptionType.DELETE in MyAnswerViewModel to locate and update the code.app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt (1)
60-68: onFailure 내부의 중첩launch는 제거하는 편이 좋습니다.이미
viewModelScope.launch안에서 실행 중이라_sideEffect.emit(...)을 직접 호출해도 됩니다. 중첩 코루틴을 줄이면 흐름이 단순해집니다.제안 diff
- }.onFailure { - viewModelScope.launch { - _sideEffect.emit( - QuestCompletedSideEffect.ShowSnackBar( - message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", - iconType = CustomSnackBarType.ALERT, - ), - ) - } - } + }.onFailure { + _sideEffect.emit( + QuestCompletedSideEffect.ShowSnackBar( + message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", + iconType = CustomSnackBarType.ALERT, + ), + ) + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt` around lines 60 - 68, In OffboardingQuestCompletedViewModel inside the onFailure block, remove the nested viewModelScope.launch and directly call _sideEffect.emit(...) from the surrounding coroutine context (you are already inside viewModelScope.launch), so replace the inner launch-wrapped emit with a direct _sideEffect.emit call (keep the same QuestCompletedSideEffect.ShowSnackBar parameters and CustomSnackBarType.ALERT).app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt (1)
92-95: 동일한 에러 스낵바 emit 로직은 헬퍼로 합치는 것을 권장합니다.현재 두 실패 분기에서 동일한 블록이 반복되어 유지보수 시 메시지/타입 변경 누락 위험이 있습니다.
♻️ 제안 diff
@@ - _sideEffect.emit( - QuestStartSideEffect.ShowSnackBar( - message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", - iconType = CustomSnackBarType.ALERT, - ), - ) + emitServerConnectionErrorSnackBar() @@ - _sideEffect.emit( - QuestStartSideEffect.ShowSnackBar( - message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", - iconType = CustomSnackBarType.ALERT, - ), - ) + emitServerConnectionErrorSnackBar() @@ + private suspend fun emitServerConnectionErrorSnackBar() { + _sideEffect.emit( + QuestStartSideEffect.ShowSnackBar( + message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", + iconType = CustomSnackBarType.ALERT, + ), + ) + }Also applies to: 132-135
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt` around lines 92 - 95, Duplicate ShowSnackBar emission with the same message/type is repeated in QuestStartViewModel (the QuestStartSideEffect.ShowSnackBar blocks at the two failure branches around the existing emits), so extract a single helper method (e.g., emitServerConnectionSnackBar or emitErrorSnackBar) inside QuestStartViewModel that constructs/emits QuestStartSideEffect.ShowSnackBar with the shared message and CustomSnackBarType.ALERT, then replace both duplicated blocks (the ones around lines 92-95 and 132-135) with calls to that helper to centralize the message/type and avoid drift.app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt (1)
7-13: 구현이 올바르며, data class 사용을 고려해 볼 수 있습니다.
SnackbarVisuals인터페이스 구현이 적절합니다. 선택적으로data class로 변경하면equals,hashCode,copy메서드를 자동으로 얻을 수 있어 테스트나 비교 시 유용할 수 있습니다.♻️ data class로 변경 제안
-class CustomSnackBarVisuals( +data class CustomSnackBarVisuals( override val message: String, val type: CustomSnackBarType, override val actionLabel: String? = null, override val withDismissAction: Boolean = false, override val duration: SnackbarDuration = SnackbarDuration.Short, ) : SnackbarVisuals🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt` around lines 7 - 13, Convert the CustomSnackBarVisuals class into a data class to automatically get equals/hashCode/copy/toString for easier testing and comparisons; update the declaration of CustomSnackBarVisuals (which implements SnackbarVisuals and references CustomSnackBarType, message, actionLabel, withDismissAction, duration) so it is declared as a data class while keeping the same primary constructor parameters and the implemented interface SnackbarVisuals.app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt (1)
6-29: 하드코딩된 문자열을 string resource로 이동하는 것을 고려해 주세요.
optionTitle값들이 직접 하드코딩되어 있습니다. 향후 다국어 지원(i18n)을 위해 string resource로 관리하는 것이 좋습니다.♻️ String resource 사용 제안
enum class OptionType( `@DrawableRes` val optionIcon: Int, - val optionTitle: String, + `@StringRes` val optionTitleRes: Int, ) { BLOCK( optionIcon = R.drawable.ic_block, - optionTitle = "사용자 차단하기", + optionTitleRes = R.string.option_block_user, ), // ... 나머지 항목도 동일하게 적용 }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt` around lines 6 - 29, The enum OptionType currently hardcodes Korean titles in the optionTitle property for entries BLOCK, REPORT, EDIT, DELETE; change optionTitle to reference string resources instead (e.g., R.string.option_block, R.string.option_report, R.string.option_edit, R.string.option_delete) and update callers to resolve the string via Context or a string provider when displaying (keep the enum values as resource IDs or store `@StringRes` ints rather than raw Strings). Ensure you add the corresponding entries to strings.xml and mark optionTitle as an Int annotated with `@StringRes` in the OptionType class.app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt (1)
122-126: 뒤로 가기 버튼이 비활성화 상태입니다.PR 목표에서 "뒤로 가기 아이콘 네비 연결"이 미완료 항목으로 언급되어 있습니다.
navigateUp콜백을MyAnswerDetailRoute에 추가하고 연결해야 합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt` around lines 122 - 126, Add a navigateUp callback to the MyAnswerDetailRoute and wire it to the back icon's click handler: update the MyAnswerDetailRoute signature to accept a navigateUp: () -> Unit parameter, pass that down to MyAnswerDetailScreen, and replace the TODO in the Modifier.noRippleClickable used for the back icon so it calls navigateUp() when clicked; ensure any callers of MyAnswerDetailRoute provide the appropriate NavController::navigateUp or equivalent lambda.app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt (1)
129-133: 뒤로 가기 버튼 클릭 핸들러가 누락되었습니다.PR 목표에서 "뒤로 가기 아이콘 네비 연결"이 미완료 항목으로 언급되어 있습니다. 이후 작업 시
navigateUp또는navigateToQuest콜백을 연결해야 합니다.이 기능을 구현하기 위한 코드를 생성해 드릴까요, 아니면 추적을 위한 이슈를 생성할까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt` around lines 129 - 133, The back icon currently lacks a click handler; wrap the Icon in a clickable surface (e.g., IconButton or Modifier.clickable) and invoke the appropriate navigation callback passed into CommonAnswerScreen (use the existing navigateUp or navigateToQuest parameter/name) to perform navigation when tapped; ensure the click target uses the same tint and accessibility by keeping contentDescription non-null (e.g., "Back") so TalkBack users get the action.app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt (1)
85-92: 일관성을 위해screenHeightDp사용을 고려해 주세요.다른 부분에서는
screenHeightDp/screenWidthDp를 사용하여 반응형 레이아웃을 구현하고 있는데,HorizontalDivider의padding(vertical = 20.dp)에서는 하드코딩된 값을 사용하고 있습니다.♻️ 수정 제안
HorizontalDivider( modifier = Modifier .fillMaxWidth() - .padding(vertical = 20.dp), + .padding(vertical = screenHeightDp(20.dp)), thickness = 1.dp, color = ByeBooTheme.colors.gray800, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt` around lines 85 - 92, Replace the hardcoded Vertical padding on HorizontalDivider in MoreOptionsBottomSheet (the Modifier.padding(vertical = 20.dp) call) with a responsive value derived from the existing screenHeightDp/screenWidthDp approach used in this file; compute the vertical padding from screenHeightDp (using the same scale factor pattern used elsewhere) and apply that computed value to Modifier.padding so the divider spacing scales with screen size.app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt (1)
88-92: 뒤로 가기 버튼이 비활성화 상태입니다.
noRippleClickable에 클릭 핸들러가 없어 뒤로 가기 아이콘이 동작하지 않습니다. TODO 주석이 있으니 이후 네비게이션 연결이 필요합니다.이 기능을 구현하는 코드를 생성해 드릴까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt` around lines 88 - 92, The back button is non-functional because Modifier.noRippleClickable has no onClick handler; in MyAnswerScreen replace the TODO with a lambda that performs navigation (e.g., Modifier.noRippleClickable { navController.popBackStack() } ) or, if NavController isn't available in this composable, add an onBackPressed/onNavigateUp: ()->Unit parameter to MyAnswerScreen and call that inside the noRippleClickable lambda (Modifier.noRippleClickable { onBackPressed() }) so the icon actually navigates back.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Line 76: The Spacer uses Modifier.padding(end = screenWidthDp(12.dp)) which
doesn't create horizontal space; replace the padding modifier with a width
modifier so the Spacer actually occupies horizontal gap (change Spacer(...
Modifier.padding(end = screenWidthDp(12.dp))) to use
Modifier.width(screenWidthDp(12.dp))) in MoreOptionsBottomSheet (also update the
second occurrence around the other Spacer noted in the comment).
In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`:
- Around line 133-137: MyAnswerDetailRoute is not receiving the answerId from
the QuestMyAnswersDetail nav route, so the UI always shows the first answer;
update the navigation composable to pass the route args into the route and
change MyAnswerViewModel to read the answerId from SavedStateHandle (use
savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId) and use that id to
load the specific answer; target symbols: composable<QuestMyAnswersDetail>,
MyAnswerDetailRoute, MyAnswerViewModel, SavedStateHandle, toRoute, answerId.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 147-148: In CommonAnswerScreen.kt the Spacer inside the Row uses
Modifier.padding(bottom = screenHeightDp(16.dp)) which has no effect because Row
lays out children horizontally; either remove the unused Spacer or replace its
modifier to produce the intended spacing: if you wanted horizontal space use
Modifier.width(...), if you wanted vertical space move the Spacer out of the Row
into a Column/parent and use Modifier.height(screenHeightDp(16.dp)) or apply the
bottom padding to the Row or parent container; update the Spacer or parent
accordingly to reflect the intended vertical/horizontal spacing.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Line 139: The Spacer inside the Row in MyAnswerDetailScreen.kt is using
Modifier.padding(bottom = screenHeightDp(16.dp)), which has no effect in a
horizontal Row; replace that Spacer with a vertical spacing approach by using a
Spacer with Modifier.height(screenHeightDp(16.dp)) or move the bottom padding to
a parent Column/Box that controls vertical spacing (refer to the Spacer instance
and the surrounding Row in MyAnswerDetailScreen.kt and mirror the fix used in
CommonAnswerScreen.kt).
- Line 64: The current code uses uiState.answers.first() which throws
NoSuchElementException for empty lists; change that to a safe access (e.g., use
firstOrNull() or getOrNull(0)) and handle the null case rather than letting it
crash — update the val answerState assignment in MyAnswerDetailScreen to use
uiState.answers.firstOrNull() (or uiState.answers.getOrNull(0)) and then either
early-return, show an empty/error UI, or provide a fallback value so downstream
code using answerState is not executed with a missing item.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 96-106: The Text composable in MyAnswerScreen currently hardcodes
the nickname string ("하츠핑하츠님의") inside the buildAnnotatedString; replace that
hardcoded text by injecting the real user nickname from the screen state (e.g.,
use uiState.nickname or a value exposed by the ViewModel) when building the
string in the Text composable (the buildAnnotatedString block used for the
header), ensuring you handle null/empty nickname with a sensible fallback.
---
Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`:
- Around line 186-193: The onClick for CommonAnswerItem is passing a hardcoded 1
to onAnswerClick; change it to pass the clicked answer's ID (e.g., use answer.id
or answer.answerId depending on the model) so the real answer identifier is
forwarded to onAnswerClick; update the onClick lambda in CommonAnswerItem to
call onAnswerClick with the answer's id property (and add a null/exists check if
the model uses a nullable id).
---
Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt`:
- Around line 7-13: Convert the CustomSnackBarVisuals class into a data class to
automatically get equals/hashCode/copy/toString for easier testing and
comparisons; update the declaration of CustomSnackBarVisuals (which implements
SnackbarVisuals and references CustomSnackBarType, message, actionLabel,
withDismissAction, duration) so it is declared as a data class while keeping the
same primary constructor parameters and the implemented interface
SnackbarVisuals.
In
`@app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt`:
- Around line 60-68: In OffboardingQuestCompletedViewModel inside the onFailure
block, remove the nested viewModelScope.launch and directly call
_sideEffect.emit(...) from the surrounding coroutine context (you are already
inside viewModelScope.launch), so replace the inner launch-wrapped emit with a
direct _sideEffect.emit call (keep the same
QuestCompletedSideEffect.ShowSnackBar parameters and CustomSnackBarType.ALERT).
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Around line 85-92: Replace the hardcoded Vertical padding on HorizontalDivider
in MoreOptionsBottomSheet (the Modifier.padding(vertical = 20.dp) call) with a
responsive value derived from the existing screenHeightDp/screenWidthDp approach
used in this file; compute the vertical padding from screenHeightDp (using the
same scale factor pattern used elsewhere) and apply that computed value to
Modifier.padding so the divider spacing scales with screen size.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt`:
- Line 60: In MyAnswerItem (file MyAnswerItem.kt) the Spacer uses
Modifier.padding(screenHeightDp(12.dp)) which adds padding both top and bottom
(totaling 24dp) instead of providing a 12dp vertical gap; change the Spacer's
modifier to Modifier.height(screenHeightDp(12.dp)) so it produces the intended
12dp vertical space (refer to the Spacer instance around the commented line and
mirror the approach used later on line 70).
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt`:
- Around line 6-29: The enum OptionType currently hardcodes Korean titles in the
optionTitle property for entries BLOCK, REPORT, EDIT, DELETE; change optionTitle
to reference string resources instead (e.g., R.string.option_block,
R.string.option_report, R.string.option_edit, R.string.option_delete) and update
callers to resolve the string via Context or a string provider when displaying
(keep the enum values as resource IDs or store `@StringRes` ints rather than raw
Strings). Ensure you add the corresponding entries to strings.xml and mark
optionTitle as an Int annotated with `@StringRes` in the OptionType class.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 129-133: The back icon currently lacks a click handler; wrap the
Icon in a clickable surface (e.g., IconButton or Modifier.clickable) and invoke
the appropriate navigation callback passed into CommonAnswerScreen (use the
existing navigateUp or navigateToQuest parameter/name) to perform navigation
when tapped; ensure the click target uses the same tint and accessibility by
keeping contentDescription non-null (e.g., "Back") so TalkBack users get the
action.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Around line 122-126: Add a navigateUp callback to the MyAnswerDetailRoute and
wire it to the back icon's click handler: update the MyAnswerDetailRoute
signature to accept a navigateUp: () -> Unit parameter, pass that down to
MyAnswerDetailScreen, and replace the TODO in the Modifier.noRippleClickable
used for the back icon so it calls navigateUp() when clicked; ensure any callers
of MyAnswerDetailRoute provide the appropriate NavController::navigateUp or
equivalent lambda.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 88-92: The back button is non-functional because
Modifier.noRippleClickable has no onClick handler; in MyAnswerScreen replace the
TODO with a lambda that performs navigation (e.g., Modifier.noRippleClickable {
navController.popBackStack() } ) or, if NavController isn't available in this
composable, add an onBackPressed/onNavigateUp: ()->Unit parameter to
MyAnswerScreen and call that inside the noRippleClickable lambda
(Modifier.noRippleClickable { onBackPressed() }) so the icon actually navigates
back.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 84-90: The current viewModelScope.launch wrapper around the
when(option) block is unnecessary because there are no suspend calls; remove the
viewModelScope.launch call and execute the when(option) directly (retaining the
OptionType.EDIT and OptionType.DELETE branches) and only reintroduce
viewModelScope.launch around the when when you implement actual asynchronous
work for those branches (or make the called functions suspend and keep the
launch). Refer to the viewModelScope.launch and the when(option) handling
OptionType.EDIT / OptionType.DELETE in MyAnswerViewModel to locate and update
the code.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt`:
- Around line 92-95: Duplicate ShowSnackBar emission with the same message/type
is repeated in QuestStartViewModel (the QuestStartSideEffect.ShowSnackBar blocks
at the two failure branches around the existing emits), so extract a single
helper method (e.g., emitServerConnectionSnackBar or emitErrorSnackBar) inside
QuestStartViewModel that constructs/emits QuestStartSideEffect.ShowSnackBar with
the shared message and CustomSnackBarType.ALERT, then replace both duplicated
blocks (the ones around lines 92-95 and 132-135) with calls to that helper to
centralize the message/type and avoid drift.
In `@app/src/main/res/drawable/ic_block.xml`:
- Around line 6-8: SVG/XML contains an unnecessary clip-path that clips the
whole canvas (the <clip-path> element with android:pathData="M0,0h24v24h-24z");
remove that <clip-path> element (and its enclosing empty group if it becomes
redundant) from ic_block.xml so the drawable is simplified without changing
rendering.
In `@app/src/main/res/drawable/ic_overflow_menu.xml`:
- Around line 1-9: Replace the hardcoded android:fillColor="#ffffff" in the
<path> of the vector drawable with a color resource or theme attribute so the
icon follows dark/light themes and can be reused; e.g. change android:fillColor
to a reference like `@color/overflow_icon` or a theme attribute like
?attr/colorOnSurface (or make the vector tintable and remove the fillColor so
callers can set app:tint or ImageView.setColorFilter), update the color resource
if needed, and ensure usages apply the intended tint/theme attribute.
In `@app/src/main/res/drawable/ic_report.xml`:
- Around line 10-26: 해당 XML의 여러 path 요소(android:strokeColor 및
android:fillColor)에 하드코딩된 색상값 "#FF3B3E"가 중복되어 있으니 colors.xml에 예: <color
name="ic_report_tint">#FF3B3E</color> 같은 리소스를 추가한 뒤 ic_report.xml의 모든
android:strokeColor 및 android:fillColor="#FF3B3E"를 `@color/ic_report_tint로` 교체하세요;
변경 대상 식별에는 각 <path> 요소의 android:pathData 값(예: "M18,16H6V9.538...",
"M4,20L20,20", "M12.005,6.5...", "M12,12.5m-1,0...")과 속성 이름(strokeColor,
fillColor)을 참고하면 됩니다.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (82)
app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBar.ktapp/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.ktapp/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.ktapp/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoScreen.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoState.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeScreen.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeUiState.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletScreen.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletViewModel.ktapp/src/main/java/com/byeboo/app/presentation/main/MainNavHost.ktapp/src/main/java/com/byeboo/app/presentation/main/MainNavigator.ktapp/src/main/java/com/byeboo/app/presentation/main/MainScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MyPageScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MypageViewModel.ktapp/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorWritingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/card/CommonAnswerItem.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.ktapp/src/main/java/com/byeboo/app/presentation/quest/model/QuestModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.ktapp/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.ktapp/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestRoute.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartState.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipState.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashState.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.ktapp/src/main/res/drawable/ic_block.xmlapp/src/main/res/drawable/ic_overflow_menu.xmlapp/src/main/res/drawable/ic_report.xmlapp/src/main/res/drawable/ic_success.xmlapp/src/main/res/drawable/ic_trash.xml
.../main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt
Outdated
Show resolved
Hide resolved
| composable<QuestMyAnswersDetail> { | ||
| MyAnswerDetailRoute( | ||
| paddingValues = paddingValues, | ||
| ) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find MyAnswerDetailRoute implementation
fd -t f "MyAnswerDetailRoute" --type fRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 57
🏁 Script executed:
# Search for MyAnswerDetailRoute function/composable definition
rg -n "fun MyAnswerDetailRoute|@Composable.*MyAnswerDetailRoute" --type=kotlinRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 201
🏁 Script executed:
# Find MyAnswerViewModel file
fd -t f "*MyAnswerViewModel*" --type fRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 373
🏁 Script executed:
# Check MyAnswerViewModel constructor and SavedStateHandle usage
rg -n "class MyAnswerViewModel|SavedStateHandle|answerId" --type=kotlin -B 2 -A 5 | grep -A 20 "MyAnswerViewModel"Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 8822
🏁 Script executed:
# Read MyAnswerDetailRoute implementation
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt | head -80Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 3779
🏁 Script executed:
# Read the full MyAnswerViewModel to see all details
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.ktRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 4635
🏁 Script executed:
# Search for QuestMyAnswersDetail route definition in QuestNavigation
rg -n "QuestMyAnswersDetail" app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt -B 2 -A 2Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 346
MyAnswerDetailRoute이 QuestMyAnswersDetail 라우트로부터 answerId를 수신하지 않습니다.
네비게이션에서 QuestMyAnswersDetail(answerId)로 이동하지만, MyAnswerDetailRoute는 이 파라미터를 받지 않습니다. 현재 구현에서는 uiState.answers.first()를 사용하므로 항상 첫 번째 답변만 표시됩니다.
MyAnswerViewModel에서 SavedStateHandle을 주입받아 라우트 파라미터로부터 answerId를 추출하도록 수정해야 합니다:
class MyAnswerViewModel
`@Inject`
constructor(
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val answerId: Long = savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId
// ... answerId를 사용하여 해당 답변 조회
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`
around lines 133 - 137, MyAnswerDetailRoute is not receiving the answerId from
the QuestMyAnswersDetail nav route, so the UI always shows the first answer;
update the navigation composable to pass the route args into the route and
change MyAnswerViewModel to read the answerId from SavedStateHandle (use
savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId) and use that id to
load the specific answer; target symbols: composable<QuestMyAnswersDetail>,
MyAnswerDetailRoute, MyAnswerViewModel, SavedStateHandle, toRoute, answerId.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
Outdated
Show resolved
Hide resolved
| modifier: Modifier = Modifier, | ||
| ) { | ||
| val scrollState = rememberScrollState() | ||
| val answerState = uiState.answers.first() |
There was a problem hiding this comment.
uiState.answers.first()는 빈 리스트에서 NoSuchElementException을 발생시킵니다.
answers 리스트가 비어있을 경우 앱이 크래시됩니다. 안전한 접근 방식을 사용하거나 빈 상태를 처리해야 합니다.
🐛 수정 제안
`@Composable`
private fun MyAnswerDetailScreen(
uiState: MyAnswerState,
paddingValues: PaddingValues,
onClickMoreOptions: () -> Unit,
onDismissBottomSheet: () -> Unit,
onOptionClick: (OptionType) -> Unit,
modifier: Modifier = Modifier,
) {
val scrollState = rememberScrollState()
- val answerState = uiState.answers.first()
+ val answerState = uiState.answers.firstOrNull() ?: return📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val answerState = uiState.answers.first() | |
| `@Composable` | |
| private fun MyAnswerDetailScreen( | |
| uiState: MyAnswerState, | |
| paddingValues: PaddingValues, | |
| onClickMoreOptions: () -> Unit, | |
| onDismissBottomSheet: () -> Unit, | |
| onOptionClick: (OptionType) -> Unit, | |
| modifier: Modifier = Modifier, | |
| ) { | |
| val scrollState = rememberScrollState() | |
| val answerState = uiState.answers.firstOrNull() ?: return |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
at line 64, The current code uses uiState.answers.first() which throws
NoSuchElementException for empty lists; change that to a safe access (e.g., use
firstOrNull() or getOrNull(0)) and handle the null case rather than letting it
crash — update the val answerState assignment in MyAnswerDetailScreen to use
uiState.answers.firstOrNull() (or uiState.answers.getOrNull(0)) and then either
early-return, show an empty/error UI, or provide a fallback value so downstream
code using answerState is not executed with a missing item.
...c/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
Outdated
Show resolved
Hide resolved
| Text( | ||
| text = | ||
| buildAnnotatedString { | ||
| append("하츠핑하츠님의") | ||
| append("\n") | ||
| append("공통퀘스트 답변이에요") | ||
| }, | ||
| color = ByeBooTheme.colors.gray50, | ||
| style = ByeBooTheme.typography.head2, | ||
| modifier = Modifier.padding(vertical = screenHeightDp(10.dp)), | ||
| ) |
There was a problem hiding this comment.
닉네임이 하드코딩되어 있습니다.
"하츠핑하츠님의"가 하드코딩되어 있습니다. 실제 사용자 닉네임은 uiState에서 가져오거나 ViewModel을 통해 주입받아야 합니다.
🔧 수정 제안
Text(
text =
buildAnnotatedString {
- append("하츠핑하츠님의")
+ append("${uiState.nickname}님의")
append("\n")
append("공통퀘스트 답변이에요")
},🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
around lines 96 - 106, The Text composable in MyAnswerScreen currently hardcodes
the nickname string ("하츠핑하츠님의") inside the buildAnnotatedString; replace that
hardcoded text by injecting the real user nickname from the screen state (e.g.,
use uiState.nickname or a value exposed by the ViewModel) when building the
string in the Text composable (the buildAnnotatedString block used for the
header), ensuring you handle null/empty nickname with a sensible fallback.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
Outdated
Show resolved
Hide resolved
|
|
||
| @Composable | ||
| private fun MyAnswerDetailTopBar( | ||
| onClickMoreOptions: () -> Unit, |
There was a problem hiding this comment.
이 탑 바를 공통 컴포넌트로 빼는건 별로일까요?
...c/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
Outdated
Show resolved
Hide resolved
| modifier = modifier, | ||
| ) | ||
|
|
||
| QuestTitle( |
There was a problem hiding this comment.
공통퀘스트는 피그마상 타이틀이 조금 다른데 같은데 확인 부탁 드립니다!
There was a problem hiding this comment.
이 부분 아직 이전 pr 병합을 못해서 일단 이렇게 썼습니다!
추후에 풀 받아온 후 수정하겠습니다!
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt (1)
19-23: 뒤로가기 콜백 파라미터 누락현재
onClickMoreOptions만 파라미터로 받고 있지만, 뒤로가기 아이콘도 클릭 가능한 상태입니다(Line 36-38). 재사용성과 완성도를 위해onClickBack콜백도 추가하는 것이 좋습니다.♻️ 제안: onClickBack 파라미터 추가
`@Composable` fun AnswerDetailTopBar( + onClickBack: () -> Unit, onClickMoreOptions: () -> Unit, modifier: Modifier = Modifier, ) {그리고 Line 36-38의
noRippleClickable에 적용:modifier = Modifier.noRippleClickable( - // Todo: 뒤로가기 + onClick = onClickBack, ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt` around lines 19 - 23, Add a missing back-click callback to the AnswerDetailTopBar composable by introducing an onClickBack: () -> Unit parameter (with a sensible default if desired) alongside the existing onClickMoreOptions; then update the back icon's noRippleClickable invocation (the click handler around the Back icon in AnswerDetailTopBar) to call onClickBack instead of being hardcoded/absent so back presses are handled by the caller.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 82-85: CommonAnswerScreen currently forwards its incoming modifier
to AnswerDetailTopBar even though that modifier is already applied to the parent
Column (see Column in CommonAnswerScreen); change the call to AnswerDetailTopBar
to pass a fresh/empty Modifier (or omit the modifier argument if optional)
instead of the external modifier to avoid double-applying the same modifier;
update the invocation of AnswerDetailTopBar in CommonAnswerScreen and ensure any
local styling needed by AnswerDetailTopBar is provided via a dedicated internal
modifier rather than the external parameter.
- Line 94: Spacer에 Modifier.padding(bottom = ...)를 사용하면 의도한 수직 간격이 적용되지 않으므로, 해당
Spacer 호출(함수/파일의 Spacer(...) 사용 부분)에서 Modifier.padding을 제거하고 대신
Modifier.height(screenHeightDp(10.dp))로 크기를 지정해 수직 여백을 명시적으로 적용하도록 변경하세요; 즉 현재의
Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp)))를
Spacer(modifier = Modifier.height(screenHeightDp(10.dp)))로 바꾸면 됩니다.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 31-38: Two Icon composables currently set contentDescription =
null (e.g., the Icon using ImageVector.vectorResource(id = R.drawable.ic_left)
with Modifier.noRippleClickable) which prevents screen readers from conveying
the button purpose; update both Icon usages (the left/back Icon and the other
Icon in the 43-52 range) to provide meaningful, localized contentDescription
strings (use string resources like R.string.back or R.string.edit/action_name)
instead of null, and only keep null if the icon is purely decorative; ensure the
descriptions match the button action invoked by the surrounding clickable
(Modifier.noRippleClickable) so accessibility tools read the correct intent.
---
Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 19-23: Add a missing back-click callback to the AnswerDetailTopBar
composable by introducing an onClickBack: () -> Unit parameter (with a sensible
default if desired) alongside the existing onClickMoreOptions; then update the
back icon's noRippleClickable invocation (the click handler around the Back icon
in AnswerDetailTopBar) to call onClickBack instead of being hardcoded/absent so
back presses are handled by the caller.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
🚧 Files skipped from review as they are similar to previous changes (2)
- app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
- app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt
...c/main/java/com/byeboo/app/presentation/quest/review/common/other/CommonOtherAnswerScreen.kt
Show resolved
Hide resolved
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
Outdated
Show resolved
Hide resolved
| Icon( | ||
| imageVector = ImageVector.vectorResource(id = R.drawable.ic_left), | ||
| contentDescription = null, | ||
| tint = ByeBooTheme.colors.gray50, | ||
| modifier = | ||
| Modifier.noRippleClickable( | ||
| // Todo: 뒤로가기 | ||
| ), |
There was a problem hiding this comment.
접근성: contentDescription 누락
두 아이콘 모두 contentDescription = null로 설정되어 있어 스크린 리더 사용자가 버튼의 용도를 알 수 없습니다.
♿ 제안: contentDescription 추가
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_left),
- contentDescription = null,
+ contentDescription = "뒤로 가기",
tint = ByeBooTheme.colors.gray50, Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_overflow_menu),
- contentDescription = null,
+ contentDescription = "더보기 옵션",
tint = ByeBooTheme.colors.white,Also applies to: 43-52
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`
around lines 31 - 38, Two Icon composables currently set contentDescription =
null (e.g., the Icon using ImageVector.vectorResource(id = R.drawable.ic_left)
with Modifier.noRippleClickable) which prevents screen readers from conveying
the button purpose; update both Icon usages (the left/back Icon and the other
Icon in the 43-52 range) to provide meaningful, localized contentDescription
strings (use string resources like R.string.back or R.string.edit/action_name)
instead of null, and only keep null if the icon is purely decorative; ensure the
descriptions match the button action invoked by the surrounding clickable
(Modifier.noRippleClickable) so accessibility tools read the correct intent.
| _sideEffect.emit( | ||
| SplashStateSideEffect.ShowSnackBar( | ||
| "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", | ||
| message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", |
There was a problem hiding this comment.
p3: message도 CustomSnackBarType에서 같이 관리하는데 어떠세요?
| import kotlinx.collections.immutable.ImmutableList | ||
| import kotlinx.collections.immutable.persistentListOf | ||
|
|
||
| data class MyAnswerState( |
There was a problem hiding this comment.
p2: 저희 data class들에 @immutable 붙이는 건 어떠세요? 전부 val 기반이라 안정성/리컴포지션 측면에서 도움될 것 같아서요!
| import androidx.annotation.DrawableRes | ||
| import com.byeboo.app.R | ||
|
|
||
| enum class OptionType( |
There was a problem hiding this comment.
p3: 차단/신고와 수정/삭제는 의도와 책임이 다르기 때문에 UI가 같다는 이유로 하나로 묶기보다 도메인 기준으로 나누는 게 더 명확할 것 같다는 생각이 듭니다.
관련해서 의견이 궁금합니다!
There was a problem hiding this comment.
일단 UI 만 고려하고 코드를 짜서 한번에 넣었습니다..ㅎㅎ
소희님 의견대로 도메인 기준으로 나누는 것이
이후 서버 연결까지 고려했을 때 더 나은 거 같습니다! 감사합니다 :)
| } | ||
| } | ||
|
|
||
| fun onMyAnswersClick() { |
There was a problem hiding this comment.
p2: 함수명 다른 것처럼 ~Clicked로 부탁드릴게요!
| ) { answer -> | ||
| CommonAnswerItem( | ||
| answer = answer, | ||
| onClick = { onAnswerClick(1) }, |
There was a problem hiding this comment.
p2: 이것도 TODO 남겨놓는게 좋을 것 같아요!
| tint = ByeBooTheme.colors.white, | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.width(screenWidthDp(12.dp))) |
| tint = ByeBooTheme.colors.error300, | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.padding(end = screenWidthDp(12.dp))) |
| modifier = | ||
| Modifier | ||
| .fillMaxWidth() | ||
| .padding(vertical = 20.dp), |
| ) | ||
| } | ||
|
|
||
| Spacer(modifier = Modifier.padding(bottom = screenHeightDp(36.dp))) |
There was a problem hiding this comment.
p2: 이거 height로 주는거 어떠세요??
.padding(bottom ) 이라는게 모호한 것 같아서요!
| ) | ||
| } | ||
|
|
||
| Spacer(modifier = Modifier.padding(screenHeightDp(12.dp))) |
There was a problem hiding this comment.
p2: height로 통일해서 써주는거 어떠세요??
| text = "Q.", | ||
| color = ByeBooTheme.colors.primary200, | ||
| style = ByeBooTheme.typography.sub2, | ||
| modifier = Modifier.padding(end = screenWidthDp(4.dp)), |
There was a problem hiding this comment.
p2: 이거 패딩보다 Row에 간격주는게 더 직관적일 것 같아요!
| Text( | ||
| text = answer.question, | ||
| color = ByeBooTheme.colors.gray100, | ||
| style = ByeBooTheme.typography.sub3, |
There was a problem hiding this comment.
p3: 질문 무조건 1줄로 와야될 것 같은데 문장이 긴 질문에 대한 처리 해줘야 될 것 같아요..!
근데 이것 관련해서 화면 설계서에 따로 내용이 없는 것 같아서 확인 한 번 해주셔야 될 것 같습니다~
| modifier | ||
| .fillMaxWidth() | ||
| .noRippleClickable { | ||
| onMyAnswerContentClick(answer.answerId) | ||
| }.background( | ||
| color = ByeBooTheme.colors.whiteAlpha5, | ||
| shape = RoundedCornerShape(12.dp), | ||
| ).padding( | ||
| horizontal = screenWidthDp(24.dp), | ||
| vertical = screenHeightDp(16.dp), | ||
| ), |
There was a problem hiding this comment.
p1: 여기 clip으로 안 해줘서 코너 부분 눌러도 클릭이 되고 있습니다..!
| import kotlinx.coroutines.flow.collectLatest | ||
|
|
||
| @Composable | ||
| fun MyAnswerRoute( |
There was a problem hiding this comment.
p2: 이 화면 같은 경우에는 지금 내용 다 서버에서 받고 있으니 UiState로 화면 분기 처리 해주면 좋을 것 같아요!
There was a problem hiding this comment.
넵! 이 부분은 서버 연결하면서 같이 반영하겠습니다!
| modifier = | ||
| modifier | ||
| .fillMaxWidth() | ||
| .background( | ||
| .noRippleClickable( | ||
| onClick = onClick, | ||
| ).background( | ||
| color = ByeBooTheme.colors.whiteAlpha5, | ||
| shape = RoundedCornerShape(12.dp), | ||
| ).padding( | ||
| horizontal = screenWidthDp(24.dp), | ||
| vertical = screenHeightDp(16.dp), | ||
| ), |
There was a problem hiding this comment.
p2: 여기도 clip 줘야 될 것 같습니다!
There was a problem hiding this comment.
p3: 이거 화면 이름에 All 넣어서 구분해주는거 어떠세요??
| questQuestion = "그 사람이 싫어하기에 내가 포기해야만 했던 일은 무엇일까?", | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp))) |
There was a problem hiding this comment.
p1: 이거 20인 것 같습니다. 확인 부탁드려요~
| ), | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.padding(bottom = screenHeightDp(16.dp))) |
There was a problem hiding this comment.
p2: 이것도 spacer height로 줍시다~
| modifier = | ||
| Modifier | ||
| .fillMaxWidth(), | ||
| contentAlignment = Alignment.Center, |
There was a problem hiding this comment.
p1: 이거 위치가 center가 아니예요!
|
|
||
| if (uiState.answers.isEmpty()) { | ||
| item { | ||
| Box( |
There was a problem hiding this comment.
p3: 그리고 가로 중앙 정렬을 위해서 밑에 Text에 fillMaxWidth를 써주던가 이거 Box 대신 Column으로 써서 horizonta center 주면 될 것 같습니다
| questQuestion = "그 사람이 싫어하기에 내가 포기해야만 했던 일은 무엇일까?", | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp))) |
There was a problem hiding this comment.
p2: 이것도 spacer height로 부탁드립니다~!
| ) { | ||
| AnswerDetailTopBar( | ||
| onClickMoreOptions = onClickMoreOptions, | ||
| modifier = modifier, |
There was a problem hiding this comment.
p2: 이거 modifier 위에서 쓰고 있느거니 여기서 modifier를 넘겨주면 안 될 것 ㅏㄱㅌ습니다.
추가로 여기 지금 modifier 관련 속성 안쓰고 있으니 아예 안 써줘도 될 것 같아요!
| ), | ||
| ) | ||
|
|
||
| fun onMyAnswerContentClick(answerId: Long) { |
There was a problem hiding this comment.
p2: 여기도 다른 화면들처럼 함수명 Clicked로 부탁드릴게요
| import com.byeboo.app.presentation.quest.review.common.component.AnswerDetailTopBar | ||
|
|
||
| @Composable | ||
| fun MyAnswerDetailRoute( |
There was a problem hiding this comment.
p3: 여기도 내용 서버에서 받아오고 있으니 UiState로 관리해주면 좋을 것 같아요!
| _uiState.update { it.copy(showBottomSheet = false) } | ||
| } | ||
|
|
||
| fun onOptionClick(option: OptionType) { |
There was a problem hiding this comment.
p2: 여기도 다른 화면들처럼 함수명 Clicked로 부탁드릴게요
| CommonAnswerModel( | ||
| answerId = -1L, | ||
| writer = "사용자닉네", | ||
| profileIconRes = -1, | ||
| displayTime = "2026-01-30", | ||
| content = "헤어진 첫날 밤이었어요. 혼자 집에 있는데 갑자기 모든 게 현실로 다가왔고, 이제 정말 끝났다는 걸 깨달았을 때... 그때가 제일 힘들었던 것 같아요.", | ||
| ), |
There was a problem hiding this comment.
p3: 이거 빈값으로 넣어주는게 낫지 않나요??
| ModalBottomSheet( | ||
| onDismissRequest = onDismissRequest, | ||
| modifier = modifier, | ||
| sheetState = sheetState, | ||
| containerColor = ByeBooTheme.colors.gray900, | ||
| scrimColor = scrimColor, | ||
| dragHandle = null, |
There was a problem hiding this comment.
p1: 여기 shape 사용해서 radius 12.dp 줘야 될 것 같습니다!
| sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), | ||
| isBackgroundDimmed: Boolean = true, | ||
| ) { | ||
| val scrimColor = if (isBackgroundDimmed) ByeBooTheme.colors.blackAlpha80 else Color.Transparent |
There was a problem hiding this comment.
p3: 이거 지금 scrimColor가 blackAlpha80로 보이는 거니까 분기처리 안해줘도 되지 않나여??
| ) { | ||
| Column( | ||
| modifier = | ||
| modifier |
There was a problem hiding this comment.
p2: 이거 Modifier 로 써줘야 될 것 같아요~
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (2)
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt (1)
59-59:⚠️ Potential issue | 🔴 Critical빈 답변 리스트에서 크래시가 발생합니다.
Line 59의
uiState.answers.first()는 데이터가 비어 있으면NoSuchElementException로 즉시 종료됩니다.🐛 제안 수정
- val answerState = uiState.answers.first() + val answerState = uiState.answers.firstOrNull() ?: return🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt` at line 59, The code crashes when uiState.answers is empty because MyAnswerDetailScreen uses uiState.answers.first(); change this to safe access (e.g., use firstOrNull() or check isEmpty()) and handle the null/empty case before proceeding: update the answerState assignment to use firstOrNull() and add a guard (early return, placeholder UI, or error state) in the MyAnswerDetailScreen rendering logic so downstream code does not assume a non-null answer.app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt (1)
6-16:⚠️ Potential issue | 🟡 Minor기본값
profileIconRes = 0이 런타임 문제를 일으킬 수 있습니다.
profileIconRes = 0은 유효하지 않은 drawable 리소스 ID입니다. UI에서 이 기본값을 사용하려 할 경우Resources.NotFoundException이 발생할 수 있습니다. nullable 타입이나 유효한 기본 리소스 사용을 고려해 주세요.,
💡 제안된 수정
data class CommonAnswerState( val answer: CommonAnswerModel = CommonAnswerModel( answerId = 0L, writer = "", - profileIconRes = 0, + profileIconRes = R.drawable.ic_profile_default, // 유효한 기본 아이콘 사용 displayTime = "", content = "", ), val showBottomSheet: Boolean = false, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt` around lines 6 - 16, The default profileIconRes = 0 is invalid and can throw Resources.NotFoundException; update CommonAnswerModel.profileIconRes to be safe by either making it nullable (Int? = null) and adjust all UI consumers to handle null (e.g., show placeholder when profileIconRes == null) or assign a valid drawable default (e.g., DEFAULT_PROFILE_ICON) and use that constant in CommonAnswerState's initializer; touch the CommonAnswerModel declaration and every place that reads profileIconRes (adapter/binding/Composables) to implement the chosen null/placeholder handling.
🧹 Nitpick comments (12)
app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt (2)
6-20: SUCCESS 타입에도 아이콘 커스터마이징 고려현재
SUCCESS는 메시지만 커스터마이징 가능하고 아이콘은 고정되어 있습니다. 향후 다양한 성공 케이스에서 다른 아이콘이 필요할 수 있으니, 확장성을 고려해 두시면 좋겠습니다. 현재 구현으로도 충분히 동작하므로 선택적 개선 사항입니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt` around lines 6 - 20, Update the SUCCESS subtype to accept an optional icon parameter so callers can override the icon; change the SUCCESS constructor signature in CustomSnackBarType to include a `@DrawableRes` icon: Int = R.drawable.ic_success (or similar default) and pass that icon into the sealed class primary constructor when constructing SUCCESS, leaving the message parameter as-is to preserve existing usage.
10-13: 하드코딩된 문자열 대신 문자열 리소스 사용 권장
ALERT타입의 메시지가 코드에 직접 하드코딩되어 있습니다. 다국어 지원(i18n)과 유지보수를 위해strings.xml의 문자열 리소스를 사용하는 것이 좋습니다.♻️ 문자열 리소스 사용 제안
strings.xml에 추가:<string name="snackbar_server_error">서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.</string>단, sealed class의 생성자에서는 Context 없이 string resource ID를 직접 사용할 수 없으므로, 다음과 같은 대안을 고려할 수 있습니다:
sealed class CustomSnackBarType( `@DrawableRes` val icon: Int, - val message: String, + `@StringRes` val messageRes: Int, ) { object ALERT : CustomSnackBarType( icon = R.drawable.ic_alert, - message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.", + messageRes = R.string.snackbar_server_error, )또는 현재 구조를 유지하고
CustomSnackBarcomposable에서 Context를 통해 리소스를 가져오는 방식도 가능합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt` around lines 10 - 13, The ALERT case in CustomSnackBarType currently hardcodes the message string; add a string resource (e.g., snackbar_server_error) to strings.xml and stop embedding raw text in CustomSnackBarType.ALERT by either (A) changing the sealed class to accept a messageResId Int (e.g., add a parameter messageResId: Int? alongside icon) and set ALERT to messageResId = R.string.snackbar_server_error, or (B) leave the sealed class unchanged but remove the hardcoded message (set message = null or empty) and update the CustomSnackBar composable to resolve the appropriate string via LocalContext.current.getString(R.string.snackbar_server_error) when rendering ALERT; pick one approach and apply it consistently (update constructors/usages of CustomSnackBarType, the ALERT object, and the CustomSnackBar composable to load the string resource).app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt (1)
66-66:UiState.Failure처리 누락 확인 필요실패 상태에서 사용자에게 피드백을 제공하지 않고 있습니다. 에러 스낵바 표시나 에러 UI를 고려해 보세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt` at line 66, BlockedUsersScreen currently ignores UiState.Failure (is UiState.Failure -> Unit); update the BlockedUsersScreen composable to handle UiState.Failure by surfacing the error (e.g., show a Snackbar via Scaffold/rememberSnackbarHostState or render an error UI) and pass the failure message from the UiState.Failure instance into that UI; modify the state handling branch that matches UiState.Failure to call snackbarHostState.showSnackbar(...) or render an ErrorView and ensure the ViewModel/UiState provides the failure message used for display.app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt (1)
289-293: 함수명을onMyAnswersClicked로 변경해주세요.다른 함수들(
onTipClicked,onQuestClicked)과 일관성을 위해~Clicked접미사를 사용해야 합니다.♻️ 수정 제안
- fun onMyAnswersClick() { + fun onMyAnswersClicked() { viewModelScope.launch { _sideEffect.emit(QuestSideEffect.NavigateToQuestMyAnswers) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt` around lines 289 - 293, Rename the ViewModel method onMyAnswersClick to onMyAnswersClicked and update all its usages/call sites accordingly (including any references in XML, navigation, tests, and callers) to keep naming consistent with onTipClicked and onQuestClicked; preserve the implementation (launching viewModelScope and emitting QuestSideEffect.NavigateToQuestMyAnswers) and update any imports or overrides if applicable so compilation remains clean.app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt (1)
83-90: HorizontalDivider의 padding 적용 방식을 확인해주세요.
Modifier.padding(screenHeightDp(20.dp))는 모든 방향(상하좌우)에 패딩을 적용합니다. Divider 위아래 간격만 주려는 의도라면vertical패딩을 사용하는 것이 명확합니다.♻️ 수정 제안
HorizontalDivider( modifier = Modifier .fillMaxWidth() - .padding(screenHeightDp(20.dp)), + .padding(vertical = screenHeightDp(20.dp)), thickness = 1.dp, color = ByeBooTheme.colors.gray800, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt` around lines 83 - 90, HorizontalDivider currently uses Modifier.padding(screenHeightDp(20.dp)) which applies padding on all sides; change it to use vertical padding only so only top/bottom spacing is affected — update the modifier on HorizontalDivider (the call that currently uses Modifier.fillMaxWidth().padding(screenHeightDp(20.dp))) to use Modifier.fillMaxWidth().padding(vertical = screenHeightDp(20.dp)) so left/right padding is not applied.app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)
85-93:onMyAnswersClick도onMyAnswersClicked로 변경이 필요합니다.
QuestViewModel의 함수명 변경에 맞춰 이 파일의 콜백 파라미터명도 일관되게onMyAnswersClicked로 변경해주세요.onQuestClick이onQuestClicked로,onTipClick이onTipClicked로 변경된 것과 동일한 패턴입니다.♻️ 수정 제안
QuestScreen( uiState = uiState, listState = listState, paddingValues = paddingValues, onQuestClick = viewModel::onQuestClicked, - onMyAnswersClick = viewModel::onMyAnswersClick, + onMyAnswersClicked = viewModel::onMyAnswersClicked, onDismissModal = viewModel::onQuitDismissModal, onTipClick = viewModel::onTipClicked, onQuestStart = viewModel::onQuestStart, onTabClick = viewModel::onTabClicked, onCommonAnswerClick = navigateToCommonAnswer, onDateChange = viewModel::onDateChange, )QuestScreen 함수 시그니처도 함께 수정:
private fun QuestScreen( uiState: QuestUiState, listState: LazyListState, paddingValues: PaddingValues, onQuestClick: (Long) -> Unit, - onMyAnswersClick: () -> Unit, + onMyAnswersClicked: () -> Unit, onDismissModal: () -> Unit,Also applies to: 102-102, 156-157
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` around lines 85 - 93, The callback name for "my answers" must be renamed to match the ViewModel change: replace all occurrences of onMyAnswersClick with onMyAnswersClicked — update the QuestScreen composable parameter name (QuestScreen(... onMyAnswersClicked: () -> Unit ...)), the call site wiring (use viewModel::onMyAnswersClicked instead of viewModel::onMyAnswersClick), and any internal uses/forwarding of onMyAnswersClick (including navigate/handler passthroughs) to the new onMyAnswersClicked identifier so names are consistent with onQuestClicked and onTipClicked.app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)
81-90: TODO 구현 및 불필요한 코루틴 스코프 정리.EDIT/DELETE 옵션이 TODO 플레이스홀더로 비어 있습니다. 현재
viewModelScope.launch블록이 빈when분기를 감싸고 있어 불필요합니다. 실제 로직이 추가될 때까지 코루틴 래핑을 제거하거나, 구현이 필요한 경우 알려주세요.,
💡 현재 상태에서의 간소화 제안
fun onOptionClicked(option: MyPostOption) { onDismissBottomSheet() - viewModelScope.launch { - when (option) { - MyPostOption.EDIT -> { /* TODO 수정 화면 이동 */ } - MyPostOption.DELETE -> { /* TODO 삭제 모달 띄우기 */ } - } + when (option) { + MyPostOption.EDIT -> { /* TODO 수정 화면 이동 */ } + MyPostOption.DELETE -> { /* TODO 삭제 모달 띄우기 */ } } }EDIT/DELETE 기능 구현을 도와드릴까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt` around lines 81 - 90, The onOptionClicked function currently wraps empty TODO branches in viewModelScope.launch and should be simplified or implemented: if you don't yet have async work, remove the unnecessary coroutine wrapper and directly call onDismissBottomSheet and the synchronous handlers for MyPostOption.EDIT and MyPostOption.DELETE; if you intend to implement behavior now, replace the TODOs inside onOptionClicked (handling MyPostOption.EDIT to navigate/open edit screen and MyPostOption.DELETE to show a delete confirmation modal) and only keep viewModelScope.launch if those handlers perform suspend work (network/DB); reference the onOptionClicked function and MyPostOption enum to locate and update the branches accordingly.app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt (3)
88-91: 뒤로가기 네비게이션 미구현 상태TODO 주석이 있고
noRippleClickable에 빈 람다가 전달되고 있습니다. PR 미완성 작업 목록에 "뒤로 가기 아이콘 네비 연결"이 포함되어 있으므로, 추후 구현이 필요합니다.뒤로가기 네비게이션 구현을 도와드릴까요?
navigateUp콜백을MyAnswerRoute에 추가하고 연결하는 방식을 제안드릴 수 있습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt` around lines 88 - 91, The no-op click handler on the back icon is left as a TODO; wire up proper navigation by adding a navigateUp: () -> Unit parameter to MyAnswerRoute (and propagate it into MyAnswerScreen), then replace the empty lambda passed to Modifier.noRippleClickable with a call to that navigateUp callback so the back icon triggers navigation (ensure MyAnswerRoute caller supplies navController::navigateUp or equivalent).
71-71: 일관성 없는 dp 사용다른 화면들과 마찬가지로
screenWidthDp(24.dp)를 사용하여 반응형 레이아웃을 유지하세요.♻️ 수정 제안
- .padding(horizontal = 24.dp) + .padding(horizontal = screenWidthDp(24.dp))
screenWidthDpimport도 추가해야 합니다:import com.byeboo.app.core.util.screenWidthDp🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt` at line 71, Replace the hard-coded horizontal padding call in MyAnswerScreen (the .padding(horizontal = 24.dp) usage) with the responsive helper screenWidthDp(24.dp) and add the import com.byeboo.app.core.util.screenWidthDp; update the padding invocation to .padding(horizontal = screenWidthDp(24.dp)) so the layout becomes responsive and consistent with other screens.
59-60:MyAnswerScreen을private으로 변경 권장Route/Screen 패턴에서 Screen 컴포저블은 일반적으로
private으로 선언하여 외부에서 직접 호출되지 않도록 합니다.QuestReviewScreen.kt와CommonAnswerScreen.kt의 패턴과 일치시키세요.♻️ 수정 제안
`@Composable` -fun MyAnswerScreen( +private fun MyAnswerScreen( uiState: MyAnswerState, onMyAnswerContentClick: (Long) -> Unit, paddingValues: PaddingValues, modifier: Modifier = Modifier, ) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt` around lines 59 - 60, MyAnswerScreen is declared public but should follow the Route/Screen pattern and be made private; change the function declaration from "fun MyAnswerScreen(...)" to "private fun MyAnswerScreen(...)" and ensure any calls are internal to the file (aligning with how QuestReviewScreen and CommonAnswerScreen are scoped) so the composable cannot be invoked externally.app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt (2)
77-77: 일관성 없는 dp 사용다른 화면들에서는
screenWidthDp(24.dp)를 사용하는데, 여기서는 raw24.dp를 직접 사용하고 있습니다. 반응형 레이아웃을 위해 일관된 유틸리티 함수 사용을 권장합니다.♻️ 수정 제안
- .padding(horizontal = 24.dp) + .padding(horizontal = screenWidthDp(24.dp))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt` at line 77, CommonAnswerScreen uses a hardcoded horizontal padding ".padding(horizontal = 24.dp)" which is inconsistent with other screens; replace the raw 24.dp with the responsive utility call "screenWidthDp(24.dp)" inside the CommonAnswerScreen composable so the padding becomes responsive and consistent with other screens.
87-92: 하드코딩된 더미 데이터 - 서버 연결 시 교체 필요
QuestTitle의stepNumber,questNumber,createdAt,questQuestion이 하드코딩되어 있습니다. PR 설명에 따르면 UI 확인용 더미 데이터로 의도된 것이지만, 실제 배포 전에uiState에서 데이터를 가져오도록 변경해야 합니다.서버 연결 시 이 부분을
uiState에서 데이터를 받아오도록 변경하는 것을 도와드릴까요?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt` around lines 87 - 92, The UI is using hardcoded dummy props for QuestTitle; replace those literals by reading from the view state (uiState) instead: pass uiState.<questField> values (e.g., uiState.currentQuest or uiState.quest's stepNumber, questNumber, createdAt, and questQuestion) into QuestTitle, handling nullability/defaults (safe calls, elvis operator or placeholder text) so the composable renders real data from uiState rather than fixed dummy values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Line 18: The import for hiltViewModel is pointing to the wrong package;
replace the incorrect import line in CommonAnswerScreen.kt (the hiltViewModel
import) with the same package used across the codebase:
androidx.hilt.navigation.compose.hiltViewModel so it matches other files like
SplashScreen.kt and MainScreen.kt and aligns with the declared dependency
androidx.hilt:hilt-navigation-compose:1.3.0.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt`:
- Around line 61-68: The current branch for OtherPostOption.BLOCK emits
CommonAnswerSideEffect.NavigateToQuest before emitting the ShowSnackBar, which
can cause the snack bar to never appear after navigation; swap the emission
order so _sideEffect.emit(CommonAnswerSideEffect.ShowSnackBar(...)) is called
before _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) (refer to
OtherPostOption.BLOCK, _sideEffect.emit, CommonAnswerSideEffect.ShowSnackBar,
and CommonAnswerSideEffect.NavigateToQuest) to ensure the snack is shown prior
to navigation.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 19-23: AnswerDetailTopBar currently exposes only
onClickMoreOptions and lacks a back-action callback, so the back icon does
nothing; add a new parameter onClickBack: () -> Unit to the AnswerDetailTopBar
composable signature and wire it to the back icon's click handler inside the
function (replace the TODO/no-op there to call onClickBack); update any call
sites of AnswerDetailTopBar to pass a suitable lambda (e.g.,
navController::popBackStack or equivalent) so the back icon performs navigation.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Around line 73-75: MyAnswerDetailScreen currently only wires
onClickMoreOptions to AnswerDetailTopBar so the back action is missing; update
MyAnswerDetailRoute -> MyAnswerDetailScreen -> AnswerDetailTopBar chain to
accept and forward a back callback (e.g., onBack or onClickBack) and invoke the
navigation back action (popBackStack()) from the route. Specifically, add an
onBack parameter to MyAnswerDetailRoute, pass it into MyAnswerDetailScreen,
forward that to AnswerDetailTopBar, and ensure AnswerDetailTopBar calls the
provided callback when the back icon is pressed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Line 26: The import for hiltViewModel in MyAnswerScreen.kt is incorrect;
replace the incorrect import
androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel with the correct compose
Hilt import androidx.hilt.navigation.compose.hiltViewModel so usages of
hiltViewModel within the MyAnswerScreen composable (or any functions referencing
hiltViewModel) resolve correctly and the module compiles.
---
Duplicate comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt`:
- Around line 6-16: The default profileIconRes = 0 is invalid and can throw
Resources.NotFoundException; update CommonAnswerModel.profileIconRes to be safe
by either making it nullable (Int? = null) and adjust all UI consumers to handle
null (e.g., show placeholder when profileIconRes == null) or assign a valid
drawable default (e.g., DEFAULT_PROFILE_ICON) and use that constant in
CommonAnswerState's initializer; touch the CommonAnswerModel declaration and
every place that reads profileIconRes (adapter/binding/Composables) to implement
the chosen null/placeholder handling.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Line 59: The code crashes when uiState.answers is empty because
MyAnswerDetailScreen uses uiState.answers.first(); change this to safe access
(e.g., use firstOrNull() or check isEmpty()) and handle the null/empty case
before proceeding: update the answerState assignment to use firstOrNull() and
add a guard (early return, placeholder UI, or error state) in the
MyAnswerDetailScreen rendering logic so downstream code does not assume a
non-null answer.
---
Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt`:
- Around line 6-20: Update the SUCCESS subtype to accept an optional icon
parameter so callers can override the icon; change the SUCCESS constructor
signature in CustomSnackBarType to include a `@DrawableRes` icon: Int =
R.drawable.ic_success (or similar default) and pass that icon into the sealed
class primary constructor when constructing SUCCESS, leaving the message
parameter as-is to preserve existing usage.
- Around line 10-13: The ALERT case in CustomSnackBarType currently hardcodes
the message string; add a string resource (e.g., snackbar_server_error) to
strings.xml and stop embedding raw text in CustomSnackBarType.ALERT by either
(A) changing the sealed class to accept a messageResId Int (e.g., add a
parameter messageResId: Int? alongside icon) and set ALERT to messageResId =
R.string.snackbar_server_error, or (B) leave the sealed class unchanged but
remove the hardcoded message (set message = null or empty) and update the
CustomSnackBar composable to resolve the appropriate string via
LocalContext.current.getString(R.string.snackbar_server_error) when rendering
ALERT; pick one approach and apply it consistently (update constructors/usages
of CustomSnackBarType, the ALERT object, and the CustomSnackBar composable to
load the string resource).
In
`@app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt`:
- Line 66: BlockedUsersScreen currently ignores UiState.Failure (is
UiState.Failure -> Unit); update the BlockedUsersScreen composable to handle
UiState.Failure by surfacing the error (e.g., show a Snackbar via
Scaffold/rememberSnackbarHostState or render an error UI) and pass the failure
message from the UiState.Failure instance into that UI; modify the state
handling branch that matches UiState.Failure to call
snackbarHostState.showSnackbar(...) or render an ErrorView and ensure the
ViewModel/UiState provides the failure message used for display.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Around line 83-90: HorizontalDivider currently uses
Modifier.padding(screenHeightDp(20.dp)) which applies padding on all sides;
change it to use vertical padding only so only top/bottom spacing is affected —
update the modifier on HorizontalDivider (the call that currently uses
Modifier.fillMaxWidth().padding(screenHeightDp(20.dp))) to use
Modifier.fillMaxWidth().padding(vertical = screenHeightDp(20.dp)) so left/right
padding is not applied.
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Around line 85-93: The callback name for "my answers" must be renamed to match
the ViewModel change: replace all occurrences of onMyAnswersClick with
onMyAnswersClicked — update the QuestScreen composable parameter name
(QuestScreen(... onMyAnswersClicked: () -> Unit ...)), the call site wiring (use
viewModel::onMyAnswersClicked instead of viewModel::onMyAnswersClick), and any
internal uses/forwarding of onMyAnswersClick (including navigate/handler
passthroughs) to the new onMyAnswersClicked identifier so names are consistent
with onQuestClicked and onTipClicked.
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt`:
- Around line 289-293: Rename the ViewModel method onMyAnswersClick to
onMyAnswersClicked and update all its usages/call sites accordingly (including
any references in XML, navigation, tests, and callers) to keep naming consistent
with onTipClicked and onQuestClicked; preserve the implementation (launching
viewModelScope and emitting QuestSideEffect.NavigateToQuestMyAnswers) and update
any imports or overrides if applicable so compilation remains clean.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Line 77: CommonAnswerScreen uses a hardcoded horizontal padding
".padding(horizontal = 24.dp)" which is inconsistent with other screens; replace
the raw 24.dp with the responsive utility call "screenWidthDp(24.dp)" inside the
CommonAnswerScreen composable so the padding becomes responsive and consistent
with other screens.
- Around line 87-92: The UI is using hardcoded dummy props for QuestTitle;
replace those literals by reading from the view state (uiState) instead: pass
uiState.<questField> values (e.g., uiState.currentQuest or uiState.quest's
stepNumber, questNumber, createdAt, and questQuestion) into QuestTitle, handling
nullability/defaults (safe calls, elvis operator or placeholder text) so the
composable renders real data from uiState rather than fixed dummy values.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 88-91: The no-op click handler on the back icon is left as a TODO;
wire up proper navigation by adding a navigateUp: () -> Unit parameter to
MyAnswerRoute (and propagate it into MyAnswerScreen), then replace the empty
lambda passed to Modifier.noRippleClickable with a call to that navigateUp
callback so the back icon triggers navigation (ensure MyAnswerRoute caller
supplies navController::navigateUp or equivalent).
- Line 71: Replace the hard-coded horizontal padding call in MyAnswerScreen (the
.padding(horizontal = 24.dp) usage) with the responsive helper
screenWidthDp(24.dp) and add the import com.byeboo.app.core.util.screenWidthDp;
update the padding invocation to .padding(horizontal = screenWidthDp(24.dp)) so
the layout becomes responsive and consistent with other screens.
- Around line 59-60: MyAnswerScreen is declared public but should follow the
Route/Screen pattern and be made private; change the function declaration from
"fun MyAnswerScreen(...)" to "private fun MyAnswerScreen(...)" and ensure any
calls are internal to the file (aligning with how QuestReviewScreen and
CommonAnswerScreen are scoped) so the composable cannot be invoked externally.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 81-90: The onOptionClicked function currently wraps empty TODO
branches in viewModelScope.launch and should be simplified or implemented: if
you don't yet have async work, remove the unnecessary coroutine wrapper and
directly call onDismissBottomSheet and the synchronous handlers for
MyPostOption.EDIT and MyPostOption.DELETE; if you intend to implement behavior
now, replace the TODOs inside onOptionClicked (handling MyPostOption.EDIT to
navigate/open edit screen and MyPostOption.DELETE to show a delete confirmation
modal) and only keep viewModelScope.launch if those handlers perform suspend
work (network/DB); reference the onOptionClicked function and MyPostOption enum
to locate and update the branches accordingly.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (73)
app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBar.ktapp/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.ktapp/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.ktapp/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoScreen.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoState.ktapp/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeScreen.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeUiState.ktapp/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletScreen.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.ktapp/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletViewModel.ktapp/src/main/java/com/byeboo/app/presentation/main/MainScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MyPageScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/MypageViewModel.ktapp/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileState.ktapp/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedState.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.ktapp/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorWritingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/card/CommonAnswerItem.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.ktapp/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.ktapp/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartState.ktapp/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipState.ktapp/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashState.ktapp/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (28)
- app/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.kt
- app/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.kt
- app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt
- app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.kt
- app/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.kt
- app/src/main/java/com/byeboo/app/presentation/home/HomeScreen.kt
- app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.kt
- app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.kt
- app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.kt
- app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.kt
- app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.kt
- app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.kt
- app/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.kt
- app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.kt
- app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.kt
- app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.kt
- app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.kt
- app/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.kt
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
Outdated
Show resolved
Hide resolved
| OtherPostOption.BLOCK -> { | ||
| _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) | ||
| _sideEffect.emit( | ||
| CommonAnswerSideEffect.ShowSnackBar( | ||
| snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."), | ||
| ), | ||
| ) | ||
| } |
There was a problem hiding this comment.
사이드 이펙트 순서 확인 필요: 스낵바가 표시되지 않을 수 있습니다.
NavigateToQuest가 ShowSnackBar보다 먼저 emit되면, 화면 전환이 즉시 발생하여 스낵바가 사용자에게 표시되지 않을 수 있습니다. 의도한 동작인지 확인해 주세요.
💡 스낵바를 먼저 표시하는 제안
OtherPostOption.BLOCK -> {
+ _sideEffect.emit(
+ CommonAnswerSideEffect.ShowSnackBar(
+ snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
+ ),
+ )
_sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest)
- _sideEffect.emit(
- CommonAnswerSideEffect.ShowSnackBar(
- snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
- ),
- )
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| OtherPostOption.BLOCK -> { | |
| _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) | |
| _sideEffect.emit( | |
| CommonAnswerSideEffect.ShowSnackBar( | |
| snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."), | |
| ), | |
| ) | |
| } | |
| OtherPostOption.BLOCK -> { | |
| _sideEffect.emit( | |
| CommonAnswerSideEffect.ShowSnackBar( | |
| snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."), | |
| ), | |
| ) | |
| _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt`
around lines 61 - 68, The current branch for OtherPostOption.BLOCK emits
CommonAnswerSideEffect.NavigateToQuest before emitting the ShowSnackBar, which
can cause the snack bar to never appear after navigation; swap the emission
order so _sideEffect.emit(CommonAnswerSideEffect.ShowSnackBar(...)) is called
before _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) (refer to
OtherPostOption.BLOCK, _sideEffect.emit, CommonAnswerSideEffect.ShowSnackBar,
and CommonAnswerSideEffect.NavigateToQuest) to ensure the snack is shown prior
to navigation.
| @Composable | ||
| fun AnswerDetailTopBar( | ||
| onClickMoreOptions: () -> Unit, | ||
| modifier: Modifier = Modifier, | ||
| ) { |
There was a problem hiding this comment.
뒤로 가기 콜백 파라미터 누락
AnswerDetailTopBar에 onClickMoreOptions 콜백은 있지만, 뒤로 가기 기능을 위한 onClickBack 콜백 파라미터가 없습니다. TODO 주석만 있고 실제 동작이 연결되지 않아 사용자가 뒤로 가기 아이콘을 탭해도 아무 동작도 하지 않습니다.
🔧 뒤로 가기 콜백 추가 제안
`@Composable`
fun AnswerDetailTopBar(
+ onClickBack: () -> Unit,
onClickMoreOptions: () -> Unit,
modifier: Modifier = Modifier,
) { Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_left),
- contentDescription = null,
+ contentDescription = "뒤로 가기",
tint = ByeBooTheme.colors.gray50,
modifier =
Modifier.noRippleClickable(
- // Todo: 뒤로가기
+ onClick = onClickBack,
),
)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`
around lines 19 - 23, AnswerDetailTopBar currently exposes only
onClickMoreOptions and lacks a back-action callback, so the back icon does
nothing; add a new parameter onClickBack: () -> Unit to the AnswerDetailTopBar
composable signature and wire it to the back icon's click handler inside the
function (replace the TODO/no-op there to call onClickBack); update any call
sites of AnswerDetailTopBar to pass a suitable lambda (e.g.,
navController::popBackStack or equivalent) so the back icon performs navigation.
| AnswerDetailTopBar( | ||
| onClickMoreOptions = onClickMoreOptions, | ||
| ) |
There was a problem hiding this comment.
상단 뒤로가기 동작이 연결되지 않아 탐색 흐름이 끊깁니다.
현재 상세 화면 상단바는 더보기만 연결되어 있고, 뒤로가기 아이콘 경로는 연결되지 않은 상태입니다. 이 화면 진입 후 상단 UI로는 이전 화면 복귀가 불가능합니다.
필요하시면 MyAnswerDetailRoute/MyAnswerDetailScreen/AnswerDetailTopBar까지 포함해 뒤로가기 콜백 연결 diff를 한 번에 정리해드리겠습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
around lines 73 - 75, MyAnswerDetailScreen currently only wires
onClickMoreOptions to AnswerDetailTopBar so the back action is missing; update
MyAnswerDetailRoute -> MyAnswerDetailScreen -> AnswerDetailTopBar chain to
accept and forward a back callback (e.g., onBack or onClickBack) and invoke the
navigation back action (popBackStack()) from the route. Specifically, add an
onBack parameter to MyAnswerDetailRoute, pass it into MyAnswerDetailScreen,
forward that to AnswerDetailTopBar, and ensure AnswerDetailTopBar calls the
provided callback when the back icon is pressed.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt (1)
1-1:⚠️ Potential issue | 🟠 Major패키지 선언 수정 필요
이 파일의 패키지 선언이 파일 위치와 일치하지 않습니다. 파일은
quest/review/my/디렉토리에 있지만, 현재 패키지는com.byeboo.app.presentation.quest.review로 선언되어 있습니다. 동일 디렉토리의 다른 파일들(QuestReviewState.kt,QuestReviewViewModel.kt)은 올바르게com.byeboo.app.presentation.quest.review.my로 선언되어 있습니다.패키지 선언을
com.byeboo.app.presentation.quest.review.my로 수정하세요. 그러면 lines 50-52의 명시적 임포트는 불필요해집니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt` at line 1, Update the package declaration in QuestReviewScreen.kt from com.byeboo.app.presentation.quest.review to com.byeboo.app.presentation.quest.review.my so it matches the file directory and sibling files (e.g., QuestReviewState, QuestReviewViewModel), and then remove the now-unnecessary explicit imports referenced around lines 50-52 (they become redundant after the package fix).
🧹 Nitpick comments (5)
app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt (1)
148-148: TODO 코멘트가 남아있습니다.AI 버튼 연결이 아직 구현되지 않았습니다. PR 설명에 "추후 반영 예정"으로 언급되어 있으니 이슈로 추적하시겠습니까?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt` at line 148, The onClick for the AI button in QuestRecordingCompleteScreen.kt currently contains a lingering TODO; replace the placeholder in the Composable where onClick = { /*Todo: ai 버튼 연결 */ } (in QuestRecordingCompleteScreen) by either wiring the real handler (call the ViewModel action or navigation method, e.g., viewModel.onAiButtonClicked() or navController.navigate(...) used elsewhere) or, if not implementing now, create a tracked issue and replace the TODO with a clear placeholder that references that issue (e.g., onClick = { /* TODO: see ISSUE-1234 */ }) so the intent is traceable and the code no longer contains an untracked TODO.app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt (1)
205-205:getQuestRecordedDetail호출 결과가 무시되고 있습니다.이 호출이 캐시 갱신 목적이라면 의도가 명확하지 않습니다. 결과를 사용하지 않는다면 주석을 추가하거나, 실패 시 처리가 필요한지 검토해 주세요.
💡 의도를 명확히 하는 제안
- questRecordedDetailRepository.getQuestRecordedDetail(questId) + // 캐시 갱신을 위한 호출 - 결과는 사용하지 않음 + questRecordedDetailRepository.getQuestRecordedDetail(questId)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt` at line 205, getQuestRecordedDetail 호출의 반환값이 전혀 사용되지 않아 결과(성공/실패/데이터)를 무시하고 있습니다; questRecordedDetailRepository.getQuestRecordedDetail(questId)의 결과를 활용하거나 의도를 명확히 하세요 — 실제로 캐시 갱신 용도라면 해당 호출을 비동기 작업(viewModelScope 등)으로 감싸고 실패 시 로깅 또는 retry/에러 처리 로직을 추가하거나, 반환값을 사용해 UI 상태를 갱신하도록 수정하고(예: 응답을 변수에 할당하거나 콜백/Flow로 처리), 단순히 무시하는 경우엔 이유를 설명하는 주석을 getQuestRecordedDetail 호출 위에 남기고 예외/에러를 최소한 로깅하도록 변경하세요.app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt (1)
240-240: 사용되지 않는 repository 호출 결과
questRecordedDetailRepository.getQuestRecordedDetail(questId)호출 결과가 사용되지 않습니다. 캐시 갱신이나 사이드 이펙트 목적이라면 주석으로 의도를 명시하거나, 불필요하다면 제거하세요.- questRecordedDetailRepository.getQuestRecordedDetail(questId) + // 캐시 갱신을 위해 호출 (결과 사용하지 않음) + questRecordedDetailRepository.getQuestRecordedDetail(questId)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt` at line 240, The call to questRecordedDetailRepository.getQuestRecordedDetail(questId) in QuestBehaviorViewModel is ignored — either consume its result, remove it, or document its side-effect intent; fix by (a) assigning the returned value to a variable and using it (e.g., update LiveData/state or handle errors) if the data is needed, (b) remove the call if it’s unnecessary, or (c) keep the call but add a clear comment explaining the intentional side-effect (cache refresh) and handle errors/logging in the surrounding function so the intent and any failures are explicit.app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt (1)
187-194:onAnswerClick콜백이 연결되지 않았습니다.
onAnswerClick파라미터가 선언되었지만CommonAnswerItem의onClick에 연결되지 않았습니다. PR 목표에 "네비게이션 연결"이 미완료 항목으로 명시되어 있으니, TODO를 명확히 남기거나 실제 연결을 구현하세요.💡 연결 구현 예시
CommonAnswerItem( answer = answer, - onClick = { /* Todo: 네비 연결 */ }, + onClick = { onAnswerClick(answer.answerId) }, modifier =구현을 도와드릴까요, 아니면 추적을 위한 이슈를 생성할까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt` around lines 187 - 194, The CommonJourneyScreen currently passes a lambda TODO to CommonAnswerItem's onClick instead of wiring the declared onAnswerClick callback; update the CommonAnswerItem invocation in CommonJourneyScreen (the call site inside CommonAnswerItem(...)) to pass the onAnswerClick parameter (e.g., onClick = { onAnswerClick(answer) }) so the screen uses the provided callback, or if navigation is intentionally deferred replace the TODO with a clear TODO comment referencing onAnswerClick (e.g., // TODO: call onAnswerClick(answer) to navigate) so intent is explicit; locate CommonAnswerItem usage in CommonJourneyScreen.kt and modify its onClick argument accordingly.app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)
95-95: 네비게이션 패턴 일관성 검토다른 클릭 핸들러들(
onQuestClick,onMyAnswersClick)은 ViewModel을 통해 Side Effect로 네비게이션을 처리하지만,onCommonAnswerClick은navigateToCommonAnswer를 직접 전달하고 있습니다.일관성을 위해 ViewModel에서 Side Effect를 발생시키는 패턴으로 통일하는 것을 고려해 주세요.
♻️ 일관된 패턴 적용 예시
QuestRoute에서:
- onCommonAnswerClick = navigateToCommonAnswer, + onCommonAnswerClick = viewModel::onCommonAnswerClicked,QuestSideEffect에 추가:
data class NavigateToCommonAnswer(val answerId: Long) : QuestSideEffectSide Effect 처리에 추가:
is QuestSideEffect.NavigateToCommonAnswer -> navigateToCommonAnswer(effect.answerId)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line 95, onCommonAnswerClick is currently wired directly to navigateToCommonAnswer, breaking the established pattern where onQuestClick and onMyAnswersClick emit navigation via QuestViewModel side effects; change onCommonAnswerClick to call a ViewModel handler that emits a new side effect (add QuestSideEffect.NavigateToCommonAnswer(answerId)), update QuestViewModel to emit that side effect instead of performing navigation, and update the side-effect consumer (where QuestSideEffect is handled) to react to QuestSideEffect.NavigateToCommonAnswer by calling navigateToCommonAnswer(effect.answerId) so all navigation flows consistently through the ViewModel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt`:
- Around line 142-156: 현재 navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail에서 상세 화면으로 이동할 때 clearStackNavOptions를 사용해 네비게이션 스택
전체를 삭제하고 있어 뒤로가기 불가능 상태가 됩니다; 의도한 동작이 아니라면 이 세 곳에서 clearStackNavOptions 대신
keepStackNavOptions를 사용하도록 수정하여 기존 스택을 유지하고 뒤로가기를 허용하세요 (참조 심볼:
navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail, clearStackNavOptions, keepStackNavOptions).
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Around line 214-216: The runCatching block that calls
context.contentResolver.openInputStream(imageUrl) is leaking the InputStream;
apply the same fix here as in uploadEditedImage(): wrap the result of
openInputStream(...) in a Kotlin use { } scope (or ensure finally closes the
stream) so the InputStream is always closed after reading bytes, e.g., replace
direct readBytes() on inputStream with inputStream.use { it.readBytes() } within
the runCatching in the function containing the current code and do the same in
uploadEditedImage().
- Around line 143-146: The runCatching block in QuestBehaviorViewModel opens an
InputStream via context.contentResolver.openInputStream(imageUrl) but never
closes it, risking resource leaks; modify the code that reads the stream (the
inputStream and imageBytes logic inside the runCatching) to use the Kotlin use {
} extension on the stream (e.g.,
context.contentResolver.openInputStream(imageUrl)?.use { /* readBytes and derive
contentType */ } ) so the stream is always closed even on exceptions, preserving
existing error handling around imageBytes and contentType retrieval.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`:
- Around line 123-128: The route is ignoring the answerId passed via navigation:
QuestCommonAnswer navigates with an answerId but CommonAnswerRoute does not
accept it and CommonAnswerViewModel hardcodes loadCommonAnswer(1L). Fix by
wiring the param through either (A) inject SavedStateHandle into
CommonAnswerViewModel and read answerId from it (use key "answerId") so
loadCommonAnswer uses the extracted value instead of 1L, or (B) change
CommonAnswerRoute signature to accept an answerId parameter and forward that to
CommonAnswerViewModel (or call loadCommonAnswer(answerId)) when initializing;
update where CommonAnswerRoute is invoked in QuestNavigation to pass the
argument accordingly.
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 90: The onCommonQuestClick handler in QuestScreen (the onCommonQuestClick
lambda) is currently an empty lambda so common-quest taps do nothing; replace
the empty lambda with a call into the appropriate ViewModel method (e.g.,
viewModel.onCommonQuestClicked(questId) or navigation handler) or, if you cannot
implement now, add a clear TODO comment and create a tracked issue referencing
QuestScreen.onCommonQuestClick to implement the navigation/logic later; ensure
the handler forwards necessary identifiers (quest id or model) and
updates/navigation are performed via the ViewModel/Navigation component rather
than handling UI logic inline.
---
Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt`:
- Line 1: Update the package declaration in QuestReviewScreen.kt from
com.byeboo.app.presentation.quest.review to
com.byeboo.app.presentation.quest.review.my so it matches the file directory and
sibling files (e.g., QuestReviewState, QuestReviewViewModel), and then remove
the now-unnecessary explicit imports referenced around lines 50-52 (they become
redundant after the package fix).
---
Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Line 240: The call to
questRecordedDetailRepository.getQuestRecordedDetail(questId) in
QuestBehaviorViewModel is ignored — either consume its result, remove it, or
document its side-effect intent; fix by (a) assigning the returned value to a
variable and using it (e.g., update LiveData/state or handle errors) if the data
is needed, (b) remove the call if it’s unnecessary, or (c) keep the call but add
a clear comment explaining the intentional side-effect (cache refresh) and
handle errors/logging in the surrounding function so the intent and any failures
are explicit.
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 95: onCommonAnswerClick is currently wired directly to
navigateToCommonAnswer, breaking the established pattern where onQuestClick and
onMyAnswersClick emit navigation via QuestViewModel side effects; change
onCommonAnswerClick to call a ViewModel handler that emits a new side effect
(add QuestSideEffect.NavigateToCommonAnswer(answerId)), update QuestViewModel to
emit that side effect instead of performing navigation, and update the
side-effect consumer (where QuestSideEffect is handled) to react to
QuestSideEffect.NavigateToCommonAnswer by calling
navigateToCommonAnswer(effect.answerId) so all navigation flows consistently
through the ViewModel.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt`:
- Line 148: The onClick for the AI button in QuestRecordingCompleteScreen.kt
currently contains a lingering TODO; replace the placeholder in the Composable
where onClick = { /*Todo: ai 버튼 연결 */ } (in QuestRecordingCompleteScreen) by
either wiring the real handler (call the ViewModel action or navigation method,
e.g., viewModel.onAiButtonClicked() or navController.navigate(...) used
elsewhere) or, if not implementing now, create a tracked issue and replace the
TODO with a clear placeholder that references that issue (e.g., onClick = { /*
TODO: see ISSUE-1234 */ }) so the intent is traceable and the code no longer
contains an untracked TODO.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt`:
- Line 205: getQuestRecordedDetail 호출의 반환값이 전혀 사용되지 않아 결과(성공/실패/데이터)를 무시하고 있습니다;
questRecordedDetailRepository.getQuestRecordedDetail(questId)의 결과를 활용하거나 의도를 명확히
하세요 — 실제로 캐시 갱신 용도라면 해당 호출을 비동기 작업(viewModelScope 등)으로 감싸고 실패 시 로깅 또는 retry/에러
처리 로직을 추가하거나, 반환값을 사용해 UI 상태를 갱신하도록 수정하고(예: 응답을 변수에 할당하거나 콜백/Flow로 처리), 단순히 무시하는
경우엔 이유를 설명하는 주석을 getQuestRecordedDetail 호출 위에 남기고 예외/에러를 최소한 로깅하도록 변경하세요.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`:
- Around line 187-194: The CommonJourneyScreen currently passes a lambda TODO to
CommonAnswerItem's onClick instead of wiring the declared onAnswerClick
callback; update the CommonAnswerItem invocation in CommonJourneyScreen (the
call site inside CommonAnswerItem(...)) to pass the onAnswerClick parameter
(e.g., onClick = { onAnswerClick(answer) }) so the screen uses the provided
callback, or if navigation is intentionally deferred replace the TODO with a
clear TODO comment referencing onAnswerClick (e.g., // TODO: call
onAnswerClick(answer) to navigate) so intent is explicit; locate
CommonAnswerItem usage in CommonJourneyScreen.kt and modify its onClick argument
accordingly.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.ktapp/src/main/java/com/byeboo/app/presentation/main/MainNavigator.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorState.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorWritingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/common/navigation/QuestCommonNavigation.ktapp/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.ktapp/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingState.ktapp/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
🚧 Files skipped from review as they are similar to previous changes (3)
- app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt
- app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
- app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt
| navigateToQuestCommonAnswer = { answerId -> | ||
| navigator.navigateToQuestCommonAnswer( | ||
| answerId = answerId, | ||
| navOptions = clearStackNavOptions, | ||
| ) | ||
| }, | ||
| navigateToQuestMyAnswers = { | ||
| navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions) | ||
| }, | ||
| navigateToQuestMyAnswerDetail = { answerId -> | ||
| navigator.navigateToQuestMyAnswerDetail( | ||
| answerId = answerId, | ||
| navOptions = clearStackNavOptions, | ||
| ) | ||
| }, |
There was a problem hiding this comment.
상세 화면 네비게이션에 clearStackNavOptions 사용 검토 필요
navigateToQuestCommonAnswer, navigateToQuestMyAnswers, navigateToQuestMyAnswerDetail에 clearStackNavOptions를 사용하면 전체 네비게이션 스택이 삭제됩니다. 이로 인해 사용자가 상세 화면에서 뒤로가기를 할 수 없게 됩니다.
다른 상세/편집 화면들(예: Line 109-115의 navigateToQuestRecordingEdit)은 keepStackNavOptions를 사용하여 뒤로가기를 지원합니다. 의도된 동작이 아니라면 keepStackNavOptions 사용을 권장합니다.
🛠️ 수정 제안
navigateToQuestCommonAnswer = { answerId ->
navigator.navigateToQuestCommonAnswer(
answerId = answerId,
- navOptions = clearStackNavOptions,
+ navOptions = keepStackNavOptions,
)
},
navigateToQuestMyAnswers = {
- navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions)
+ navigator.navigateToQuestMyAnswers(navOptions = keepStackNavOptions)
},
navigateToQuestMyAnswerDetail = { answerId ->
navigator.navigateToQuestMyAnswerDetail(
answerId = answerId,
- navOptions = clearStackNavOptions,
+ navOptions = keepStackNavOptions,
)
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| navigateToQuestCommonAnswer = { answerId -> | |
| navigator.navigateToQuestCommonAnswer( | |
| answerId = answerId, | |
| navOptions = clearStackNavOptions, | |
| ) | |
| }, | |
| navigateToQuestMyAnswers = { | |
| navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions) | |
| }, | |
| navigateToQuestMyAnswerDetail = { answerId -> | |
| navigator.navigateToQuestMyAnswerDetail( | |
| answerId = answerId, | |
| navOptions = clearStackNavOptions, | |
| ) | |
| }, | |
| navigateToQuestCommonAnswer = { answerId -> | |
| navigator.navigateToQuestCommonAnswer( | |
| answerId = answerId, | |
| navOptions = keepStackNavOptions, | |
| ) | |
| }, | |
| navigateToQuestMyAnswers = { | |
| navigator.navigateToQuestMyAnswers(navOptions = keepStackNavOptions) | |
| }, | |
| navigateToQuestMyAnswerDetail = { answerId -> | |
| navigator.navigateToQuestMyAnswerDetail( | |
| answerId = answerId, | |
| navOptions = keepStackNavOptions, | |
| ) | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt` around
lines 142 - 156, 현재 navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail에서 상세 화면으로 이동할 때 clearStackNavOptions를 사용해 네비게이션 스택
전체를 삭제하고 있어 뒤로가기 불가능 상태가 됩니다; 의도한 동작이 아니라면 이 세 곳에서 clearStackNavOptions 대신
keepStackNavOptions를 사용하도록 수정하여 기존 스택을 유지하고 뒤로가기를 허용하세요 (참조 심볼:
navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail, clearStackNavOptions, keepStackNavOptions).
| runCatching { | ||
| val inputStream = context.contentResolver.openInputStream(imageUrl) | ||
| val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.") | ||
| val contentType = context.contentResolver.getType(imageUrl).toString() |
There was a problem hiding this comment.
InputStream 리소스 누수 가능성
openInputStream()으로 열린 스트림이 명시적으로 닫히지 않습니다. 예외 발생 시 리소스가 누수될 수 있습니다. .use {} 블록을 사용하여 스트림을 자동으로 닫도록 수정하세요.
🐛 리소스 누수 수정 제안
runCatching {
- val inputStream = context.contentResolver.openInputStream(imageUrl)
- val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
+ val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream ->
+ inputStream.readBytes()
+ } ?: error("이미지 파일을 읽을 수 없습니다.")
val contentType = context.contentResolver.getType(imageUrl).toString()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| runCatching { | |
| val inputStream = context.contentResolver.openInputStream(imageUrl) | |
| val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.") | |
| val contentType = context.contentResolver.getType(imageUrl).toString() | |
| runCatching { | |
| val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream -> | |
| inputStream.readBytes() | |
| } ?: error("이미지 파일을 읽을 수 없습니다.") | |
| val contentType = context.contentResolver.getType(imageUrl).toString() |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
around lines 143 - 146, The runCatching block in QuestBehaviorViewModel opens an
InputStream via context.contentResolver.openInputStream(imageUrl) but never
closes it, risking resource leaks; modify the code that reads the stream (the
inputStream and imageBytes logic inside the runCatching) to use the Kotlin use {
} extension on the stream (e.g.,
context.contentResolver.openInputStream(imageUrl)?.use { /* readBytes and derive
contentType */ } ) so the stream is always closed even on exceptions, preserving
existing error handling around imageBytes and contentType retrieval.
| runCatching { | ||
| val inputStream = context.contentResolver.openInputStream(imageUrl) | ||
| val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.") |
There was a problem hiding this comment.
동일한 InputStream 리소스 누수 문제
uploadEditedImage()에서도 동일하게 openInputStream()의 결과가 닫히지 않습니다.
🐛 수정 제안
runCatching {
- val inputStream = context.contentResolver.openInputStream(imageUrl)
- val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
+ val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream ->
+ inputStream.readBytes()
+ } ?: error("이미지 파일을 읽을 수 없습니다.")
val contentType = context.contentResolver.getType(imageUrl).toString()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
around lines 214 - 216, The runCatching block that calls
context.contentResolver.openInputStream(imageUrl) is leaking the InputStream;
apply the same fix here as in uploadEditedImage(): wrap the result of
openInputStream(...) in a Kotlin use { } scope (or ensure finally closes the
stream) so the InputStream is always closed after reading bytes, e.g., replace
direct readBytes() on inputStream with inputStream.use { it.readBytes() } within
the runCatching in the function containing the current code and do the same in
uploadEditedImage().
| composable<QuestCommonAnswer> { | ||
| CommonAnswerRoute( | ||
| navigateToQuest = navigateToQuest, | ||
| paddingValues = paddingValues, | ||
| ) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's examine the QuestNavigation.kt file around the mentioned lines
cd /
find . -name "QuestNavigation.kt" -type f 2>/dev/null | head -5Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 176
🏁 Script executed:
#!/bin/bash
# Also search for CommonAnswerRoute and CommonAnswerViewModel definitions
fd -e kt -x rg -l "CommonAnswerRoute|CommonAnswerViewModel" {} + 2>/dev/null | head -20Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 349
🏁 Script executed:
#!/bin/bash
# Search for the QuestCommonAnswer route definition
rg "QuestCommonAnswer|@Serializable" --type=kotlin | head -30Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 3267
🏁 Script executed:
#!/bin/bash
# Check the QuestCommonAnswer data class definition
rg -A 5 "data class QuestCommonAnswer" app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestRoute.ktRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 188
🏁 Script executed:
#!/bin/bash
# Check the CommonAnswerViewModel for SavedStateHandle usage
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.ktRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 3631
🏁 Script executed:
#!/bin/bash
# Check CommonAnswerScreen.kt to find CommonAnswerRoute
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.ktRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 4820
🏁 Script executed:
#!/bin/bash
# Check the QuestNavigation.kt file around the mentioned lines (120-135)
sed -n '110,140p' app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.ktRepository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID
Length of output: 1031
answerId 파라미터가 CommonAnswerViewModel에서 전혀 사용되지 않습니다.
QuestCommonAnswer(answerId)로 네비게이션하지만, CommonAnswerRoute는 이 파라미터를 받지 않으며, CommonAnswerViewModel도 SavedStateHandle을 사용하지 않습니다. 대신 loadCommonAnswer(1L)에서 answerId를 하드코딩하고 있어서 네비게이션할 때 전달한 answerId 값이 완전히 무시됩니다.
CommonAnswerViewModel 생성자에 SavedStateHandle을 주입하여 경로 인자에서 answerId를 추출하거나, CommonAnswerRoute를 통해 answerId를 명시적으로 전달하도록 수정이 필요합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`
around lines 123 - 128, The route is ignoring the answerId passed via
navigation: QuestCommonAnswer navigates with an answerId but CommonAnswerRoute
does not accept it and CommonAnswerViewModel hardcodes loadCommonAnswer(1L). Fix
by wiring the param through either (A) inject SavedStateHandle into
CommonAnswerViewModel and read answerId from it (use key "answerId") so
loadCommonAnswer uses the extracted value instead of 1L, or (B) change
CommonAnswerRoute signature to accept an answerId parameter and forward that to
CommonAnswerViewModel (or call loadCommonAnswer(answerId)) when initializing;
update where CommonAnswerRoute is invoked in QuestNavigation to pass the
argument accordingly.
| onCommonQuestClick = navigateToQuestCommon, | ||
| onQuestClick = viewModel::onQuestClicked, | ||
| onMyAnswersClick = viewModel::onMyAnswersClicked, | ||
| onCommonQuestClick = {/* 이동 관련 로직 뷰모델에 작성 */}, |
There was a problem hiding this comment.
미구현 로직: onCommonQuestClick 빈 람다
onCommonQuestClick이 빈 람다로 할당되어 있습니다. PR 설명의 미완료 작업 목록과 관련이 있는 것으로 보이나, 이 상태로 머지되면 공통 퀘스트 클릭 시 아무 동작도 하지 않습니다.
TODO 주석이나 별도 이슈로 추적하는 것을 권장합니다.
해당 로직 구현을 위한 이슈를 생성해 드릴까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line
90, The onCommonQuestClick handler in QuestScreen (the onCommonQuestClick
lambda) is currently an empty lambda so common-quest taps do nothing; replace
the empty lambda with a call into the appropriate ViewModel method (e.g.,
viewModel.onCommonQuestClicked(questId) or navigation handler) or, if you cannot
implement now, add a clear TODO comment and create a tracked issue referencing
QuestScreen.onCommonQuestClick to implement the navigation/logic later; ensure
the handler forwards necessary identifiers (quest id or model) and
updates/navigation are performed via the ViewModel/Navigation component rather
than handling UI logic inline.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt (1)
133-139:⚠️ Potential issue | 🟠 Major업로드 로딩 상태가 해제되지 않아 UI가 고정될 수 있습니다.
onSaveClicked에서isUploading = true설정 후, 성공/실패 모두false로 되돌리지 않고 있습니다. 또한 이미지가 없을 때 조기 반환되면 로딩 상태가 유지될 수 있습니다.🔧 수정 제안
fun onSaveClicked(context: Context) { viewModelScope.launch { - _uiState.update { it.copy(isUploading = true) } - val state = _uiState.value - val imageUrl = state.selectedImageUri ?: return@launch + val imageUrl = state.selectedImageUri ?: return@launch + _uiState.update { it.copy(isUploading = true) } val questId = state.questId val answer = state.questAnswer val emotion = state.selectedEmotion?.toData().orEmpty() runCatching { val inputStream = context.contentResolver.openInputStream(imageUrl) val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.") val contentType = context.contentResolver.getType(imageUrl).toString() val imageKey = UUID.randomUUID().toString() @@ }.onFailure { _sideEffect.emit( QuestBehaviorSideEffect.ShowSnackBar( snackBarType = CustomSnackBarType.ALERT, ), ) } + _uiState.update { it.copy(isUploading = false) } } }Also applies to: 169-181
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt` around lines 133 - 139, onSaveClicked sets _uiState.isUploading = true but never resets it on early return, success, or failure; wrap the upload/save logic in a try/finally (or ensure all return paths) so that _uiState.update { it.copy(isUploading = false) } runs on every exit, and handle the case where selectedImageUri is null by clearing isUploading before returning; apply the same fix to the other upload/save handler in this file (the analogous block referenced at lines 169-181) so both handlers always clear the uploading flag.
♻️ Duplicate comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)
90-90:⚠️ Potential issue | 🟡 Minor
onCommonQuestClick가 no-op이라 공통 여정 퀘스트 탭 동작이 막혀 있습니다.Line [90]에서 빈 람다를 넘겨 클릭 시 아무 처리도 실행되지 않습니다. 이 상태면
NavigateToQuestCommonWriting분기도 실사용에서 트리거되지 않습니다.🔧 수정 제안
- onCommonQuestClick = { /* 이동 관련 로직 뷰모델에 작성 */ }, + onCommonQuestClick = viewModel::onCommonQuestClicked,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line 90, The onCommonQuestClick passed into QuestScreen is a no-op which prevents the NavigateToQuestCommonWriting branch from ever being triggered; replace the empty lambda with the view model navigation handler (or a lambda that calls the navigation/event method) so clicks forward to NavigateToQuestCommonWriting. Locate the QuestScreen call site where onCommonQuestClick is set and pass the appropriate function from the corresponding ViewModel (e.g., viewModel::onCommonQuestClick or a lambda invoking viewModel.navigateTo(NavigateToQuestCommonWriting)) ensuring the handler emulates the same signature as onCommonQuestClick.
🧹 Nitpick comments (2)
app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt (1)
192-195: 공개 API 명칭 변경에는 임시 호환 레이어를 두는 것을 권장합니다.기능은 정상으로 보입니다. 다만 병행 작업 브랜치가 많다면 기존 메서드명을
@Deprecatedalias로 잠시 유지하면 머지 충돌과 호출부 일괄 수정 부담을 줄일 수 있습니다.호환 alias 예시
+ `@Deprecated`( + message = "Use navigateToQuestCommonWriting(questId)", + replaceWith = ReplaceWith("navigateToQuestCommonWriting(questId)") + ) + fun navigateToQuestCommon(questId: Long) { + navigateToQuestCommonWriting(questId) + } + fun navigateToQuestCommonWriting(questId: Long) { navController.navigateToQuestCommonWriting( questId = questId, ) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt` around lines 192 - 195, Add a temporary compatibility alias that preserves the old public API name and delegates to the new function: declare a `@Deprecated` annotated method (e.g., navigateToQuestWriting(questId: Long)) that simply calls navigateToQuestCommonWriting(questId), so existing callers keep working while you migrate call sites; mark it with a deprecation message and target ReplaceWith pointing to navigateToQuestCommonWriting to guide callers to the new API.app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)
30-69:init에서 더미 데이터를 고정 주입하는 구조는 분리하는 것이 안전합니다.현재 구조는 실제 데이터 연동 시 교체 누락 위험이 있어, 더미 공급을 별도 provider/fake repository로 분리하거나 빌드/플래그 기반으로 제한하는 편이 좋습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt` around lines 30 - 69, The init block in MyAnswerViewModel directly injects test data via getDummyAnswers(), which risks leftover dummy data in production; refactor by extracting getDummyAnswers() into a separate FakeAnswersProvider or a FakeAnswersRepository and add a constructor parameter (e.g., answersRepository or initialAnswers: ImmutableList<MyAnswerModel>? = null) to MyAnswerViewModel so production callers pass real data while tests/preview can pass the fake provider or list; update init to use the injected repository/provider or the nullable initialAnswers and remove hardcoded dummy injection from the view model.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 85-96: The onOptionClicked handler currently does nothing for
MyPostOption.EDIT and MyPostOption.DELETE; update onOptionClicked in
MyAnswerViewModel to emit appropriate side effects (e.g.,
MyAnswerSideEffect.NavigateToEdit(postId) for EDIT and
MyAnswerSideEffect.ShowDeleteConfirmation(postId) for DELETE) via the
ViewModel's side-effect emitter (e.g., sideEffect/ _sideEffect/emit or send in
viewModelScope) so UI can navigate or open a delete modal; ensure you pass the
relevant identifier (postId) or payload and keep emissions inside the existing
viewModelScope.launch block.
---
Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Around line 133-139: onSaveClicked sets _uiState.isUploading = true but never
resets it on early return, success, or failure; wrap the upload/save logic in a
try/finally (or ensure all return paths) so that _uiState.update {
it.copy(isUploading = false) } runs on every exit, and handle the case where
selectedImageUri is null by clearing isUploading before returning; apply the
same fix to the other upload/save handler in this file (the analogous block
referenced at lines 169-181) so both handlers always clear the uploading flag.
---
Duplicate comments:
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 90: The onCommonQuestClick passed into QuestScreen is a no-op which
prevents the NavigateToQuestCommonWriting branch from ever being triggered;
replace the empty lambda with the view model navigation handler (or a lambda
that calls the navigation/event method) so clicks forward to
NavigateToQuestCommonWriting. Locate the QuestScreen call site where
onCommonQuestClick is set and pass the appropriate function from the
corresponding ViewModel (e.g., viewModel::onCommonQuestClick or a lambda
invoking viewModel.navigateTo(NavigateToQuestCommonWriting)) ensuring the
handler emulates the same signature as onCommonQuestClick.
---
Nitpick comments:
In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt`:
- Around line 192-195: Add a temporary compatibility alias that preserves the
old public API name and delegates to the new function: declare a `@Deprecated`
annotated method (e.g., navigateToQuestWriting(questId: Long)) that simply calls
navigateToQuestCommonWriting(questId), so existing callers keep working while
you migrate call sites; mark it with a deprecation message and target
ReplaceWith pointing to navigateToQuestCommonWriting to guide callers to the new
API.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 30-69: The init block in MyAnswerViewModel directly injects test
data via getDummyAnswers(), which risks leftover dummy data in production;
refactor by extracting getDummyAnswers() into a separate FakeAnswersProvider or
a FakeAnswersRepository and add a constructor parameter (e.g., answersRepository
or initialAnswers: ImmutableList<MyAnswerModel>? = null) to MyAnswerViewModel so
production callers pass real data while tests/preview can pass the fake provider
or list; update init to use the injected repository/provider or the nullable
initialAnswers and remove hardcoded dummy injection from the view model.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.ktapp/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.ktapp/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.ktapp/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt
| fun onOptionClicked(option: MyPostOption) { | ||
| onDismissBottomSheet() | ||
|
|
||
| viewModelScope.launch { | ||
| when (option) { | ||
| MyPostOption.EDIT -> { // TODO 수정 화면 이동 | ||
| } | ||
|
|
||
| MyPostOption.DELETE -> { // TODO 삭제 모달 띄우기 | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
옵션 클릭 처리(EDIT/DELETE)가 현재 no-op입니다.
분기 내부가 비어 있어 사용자 액션이 실제 기능으로 이어지지 않습니다. 머지 전 최소한 side effect emit(네비게이션/모달 트리거) 또는 UI에서 진입 차단이 필요합니다.
원하시면 MyAnswerSideEffect 확장 포함해서 EDIT/DELETE 동작 연결안(네비 + 삭제 모달 트리거) 바로 작성해드릴게요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`
around lines 85 - 96, The onOptionClicked handler currently does nothing for
MyPostOption.EDIT and MyPostOption.DELETE; update onOptionClicked in
MyAnswerViewModel to emit appropriate side effects (e.g.,
MyAnswerSideEffect.NavigateToEdit(postId) for EDIT and
MyAnswerSideEffect.ShowDeleteConfirmation(postId) for DELETE) via the
ViewModel's side-effect emitter (e.g., sideEffect/ _sideEffect/emit or send in
viewModelScope) so UI can navigate or open a delete modal; ensure you pass the
relevant identifier (postId) or payload and keep emissions inside the existing
viewModelScope.launch block.
Related issue 🛠
Work Description 📝
Screenshot 📸
_.mp4
_.mp4
Uncompleted Tasks 😅
PR Point 📌
더미데이터 넣어서 UI만 확인할 수 있게끔 했습니다!
모달 추가는 코리 반영하면서 넣어놓을게요!
이번 PR 실수가 많을 거 같아요 열.코로 많은 지적해주세요 ㅎㅎ
이번 스프린트에서 스낵바 아이콘이 하나 더 추가됐는데요!
아이콘 타입 이넘 활용해서 넣고, 스낵바 사용하는 모든 화면 수정했습니다 !
확인 부탁드려요! 🙇♀️
자잘한 수정 때문에 건든 파일이 많네요.. 여기 부분 위주로 봐주시면 돼요!
트러블 슈팅 💥
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항